1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-03-27 00:19:39 +01:00
unleash.unleash/website/src/components/UserFeedback/index.jsx
2022-02-28 22:29:27 +01:00

386 lines
14 KiB
JavaScript

import React from 'react';
import styles from './styles.module.css';
import CloseIcon from '@site/src/icons/close';
const join = (...cs) => cs.join(' ');
export const initialData = {
currentStep: 1,
data: {
score: undefined,
comment: undefined,
customerType: undefined,
},
};
const fetchData = (initialData) => {
const localstorageKey = 'user-feedback-v1';
return {
currentStep: 1,
...initialData,
data: {
score: undefined,
comment: undefined,
customerType: undefined,
...initialData?.data,
},
initialized: Date.now(),
closedOrCompleted: false,
};
// check localstorage
// populate if there is
};
const stateReducer = (state, message) => {
switch (message.kind) {
case 'clear':
return fetchData(seedData);
case 'set score':
return {
...state,
data: { ...state.data, score: message.data },
};
case 'set comment':
return {
...state,
data: { ...state.data, comment: message.data },
};
case 'set customer type':
return {
...state,
data: { ...state.data, customerType: message.data },
};
case 'step forward':
return {
...state,
currentStep: Math.min(state.currentStep + 1, 4),
};
case 'step back':
return {
...state,
currentStep: Math.max(state.currentStep - 1, 1),
};
}
return state;
};
export const FeedbackWrapper = ({ seedData, open }) => {
const [feedbackIsOpen, setFeedbackIsOpen] = React.useState(open);
const [manuallyOpened, setManuallyOpened] = React.useState(open);
const [state, dispatch] = React.useReducer(
stateReducer,
seedData,
fetchData,
);
console.log(state, state.data);
const clear = () => dispatch({ kind: 'clear' });
const stepForward = () => {
console.log('stepping forward!');
dispatch({ kind: 'step forward' });
};
const stepBack = () => dispatch({ kind: 'step back' });
const setScore = (score) => dispatch({ kind: 'set score', data: score });
const setComment = (comment) =>
dispatch({ kind: 'set comment', data: comment });
const setCustomerType = (customerType) =>
dispatch({ kind: 'set customer type', data: customerType });
const submitFeedback = () => {
console.log('send feedback here ');
stepForward();
};
const visuallyHidden = (stepNumber) => state.currentStep !== stepNumber;
const isHidden = (stepNumber) =>
!feedbackIsOpen || visuallyHidden(stepNumber);
const Step1 = () => {
const hidden = isHidden(1);
const [newValue, setNewValue] = React.useState(state.data.score);
return (
<form
className={visuallyHidden(1) ? styles['invisible'] : ''}
onSubmit={(e) => {
e.preventDefault();
setScore(newValue);
stepForward();
}}
aria-hidden={hidden}
>
<fieldset disabled={hidden}>
<p>
<span className="visually-hidden">
On a scale from 1 to 5 where 1 is very unsatisfied
and 5 is very satisfied,
</span>{' '}
How would you rate your overall satisfaction with the
Unleash documentation?
</p>
<div className={styles['satisfaction-input-container']}>
<span
aria-hidden="true"
className={
styles['satisfaction-input-visual-label']
}
>
Very unsatisfied
</span>
<span className={styles['satisfaction-input-inputs']}>
{[1, 2, 3, 4, 5].map((n, i) => (
<span key={`input-group-${n}`}>
<input
className={join(
'visually-hidden',
styles[
'user-satisfaction-score-input'
],
)}
required
id={`user-satisfaction-score-${n}`}
name="satisfaction-level"
type="radio"
value={n}
defaultChecked={n === state.data.score}
onChange={(e) => {
const value = parseInt(
e.target.value,
);
console.log('the value is', value);
setNewValue(value);
}}
autoFocus={
manuallyOpened
? state.data.score
? state.data.score === n
: i === 0
: false
}
/>
<label
className={
styles[
'user-satisfaction-score-label'
]
}
htmlFor={`user-satisfaction-score-${n}`}
>
{n}
</label>
</span>
))}
</span>
<span
aria-hidden="true"
className={
styles['satisfaction-input-visual-label']
}
>
Very satisfied
</span>
</div>
<div className={styles['button-container']}>
<button type="submit">Next</button>
</div>
</fieldset>
</form>
);
};
const Step2 = () => {
const hidden = isHidden(2);
const textareaId = 'feedback-comment-input';
const saveComment = () =>
setComment(document.getElementById(textareaId).value);
return (
<form
className={visuallyHidden(2) ? styles['invisible'] : ''}
aria-hidden={hidden}
onSubmit={(e) => {
e.preventDefault();
saveComment();
stepForward();
}}
>
<fieldset disabled={hidden}>
<label htmlFor={textareaId}>
What would you like to see improved in the Unleash
documentation?
</label>
<textarea
id={textareaId}
name=""
rows="3"
autoFocus
defaultValue={state.data.comment}
></textarea>
<div className={styles['button-container']}>
<button type="submit">Next</button>
<button
className={styles['button-secondary']}
type="button"
onClick={() => {
saveComment();
stepForward();
}}
>
Skip
</button>
<button
className={styles['button-secondary']}
type="button"
onClick={() => {
saveComment();
stepBack();
}}
>
Back
</button>
</div>
</fieldset>
</form>
);
};
const Step3 = () => {
const hidden = isHidden(3);
const [value, setValue] = React.useState(state.data.customerType);
return (
<form
className={visuallyHidden(3) ? styles['invisible'] : ''}
aria-hidden={hidden}
onSubmit={(e) => {
e.preventDefault();
setCustomerType(value);
submitFeedback();
}}
>
<fieldset disabled={hidden}>
<span>
Finally, are you a paying customer or an open source
customer of Unleash?
</span>
<div className={styles['customer-type-inputs']}>
{[
['a', 'paying', 'paying'],
['an', 'open source', 'opensource'],
].map(([article, customerType, key], i) => (
<span key={`input-group-${key}`}>
<input
autoFocus={
state.data.customerType
? state.data.customerType === key
: i === 0
}
id={`customer-type-${key}`}
className={styles['customer-type-input']}
name="customer-type"
type="radio"
value={key}
defaultChecked={
key === state.data.customerType
}
onChange={(e) => {
const value = e.target.value;
setValue(value);
}}
/>
<label
className={styles['customer-type-label']}
htmlFor={`customer-type-${key}`}
>
I'm {article} {customerType} customer
</label>
</span>
))}
</div>
<div className={styles['button-container']}>
<button type="submit">Submit feedback</button>
<button
className={styles['button-secondary']}
type="button"
onClick={() => {
setCustomerType(value);
stepBack();
}}
>
Back
</button>
</div>
</fieldset>
</form>
);
};
const Step4 = () => {
const hidden = isHidden(4);
return (
<div className={visuallyHidden(4) ? styles['invisible'] : ''}>
<p className={styles['thank-you']}>Thank you! 🙌</p>
<button
className={styles['button-secondary']}
disabled={hidden}
onClick={() => setFeedbackIsOpen(false)}
autoFocus
>
close
</button>
</div>
);
};
return (
<div className={styles['user-feedback-container']}>
<button
aria-hidden={feedbackIsOpen}
className={join(
styles['open-feedback-button'],
styles['primary-button'],
)}
disabled={feedbackIsOpen}
onClick={() => {
setFeedbackIsOpen(true);
setManuallyOpened(true);
}}
>
<span>Feedback</span>
</button>
<article
aria-hidden={!feedbackIsOpen}
className={join(
styles['user-feedback'],
feedbackIsOpen ? '' : styles['invisible'],
)}
>
<div className={styles['close-button-row']}>
<button
onClick={() => setFeedbackIsOpen(false)}
className={styles['close-button']}
disabled={!feedbackIsOpen}
>
<span className="visually-hidden">
close feedback popup
</span>
<CloseIcon />
</button>
</div>
<div className={styles['form-section-container']}>
<Step1 />
<Step2 />
<Step3 />
<Step4 />
</div>
</article>
</div>
);
};