diff --git a/package.json b/package.json index 04b361c4f0..1d08720aaa 100644 --- a/package.json +++ b/package.json @@ -118,6 +118,8 @@ }, "devDependencies": { "@babel/core": "7.17.4", + "@docusaurus/module-type-aliases": "^2.0.0-beta.16", + "@tsconfig/docusaurus": "^1.0.4", "@types/bcryptjs": "2.4.2", "@types/express": "4.17.13", "@types/express-session": "1.17.4", @@ -159,7 +161,7 @@ "ts-jest": "27.1.3", "ts-node": "10.5.0", "tsc-watch": "4.6.0", - "typescript": "4.5.5" + "typescript": "^4.6.2" }, "resolutions": { "db-migrate/rc/minimist": "^1.2.5", diff --git a/website/src/components/UserFeedback/index.jsx b/website/src/components/UserFeedback/index.tsx similarity index 89% rename from website/src/components/UserFeedback/index.jsx rename to website/src/components/UserFeedback/index.tsx index 1ca2db795e..598ead6cce 100644 --- a/website/src/components/UserFeedback/index.jsx +++ b/website/src/components/UserFeedback/index.tsx @@ -3,9 +3,25 @@ import styles from './styles.module.css'; import CloseIcon from '@site/src/icons/close'; import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; -const join = (...cs) => cs.join(' '); +const join = (...cs: string[]) => cs.join(' '); -const clearedData = { +type CustomerType = 'open source' | 'paying'; + +type InitialData = { + currentStep: number; + data: { + score: undefined | number; + comment: undefined | string; + customerType: undefined | CustomerType; + }; + closedOrCompleted: boolean; +}; + +type CompleteData = InitialData & { + initialized: number; +}; + +const clearedData: InitialData = { currentStep: 1, data: { score: undefined, @@ -16,7 +32,7 @@ const clearedData = { }; const localstorageKey = 'user-feedback-v1'; -const populateData = (initialData) => { +const populateData = (initialData: InitialData): CompleteData => { // if we get seed data, use that. Otherwise, check if the last entry in // localstorage was completed. If not, use that as base. @@ -29,10 +45,10 @@ const populateData = (initialData) => { if (userFeedbackLog) { const mostRecentTimestamp = Math.max( - ...Object.keys(userFeedbackLog), + ...Object.keys(userFeedbackLog).map(parseInt), ); const mostRecent = userFeedbackLog[mostRecentTimestamp]; - if (!mostRecent.closedOrCompleted) { + if (mostRecent && !mostRecent.closedOrCompleted) { return mostRecent; } } @@ -52,14 +68,13 @@ const populateData = (initialData) => { ...seedData?.data, }, initialized: Date.now(), - userClosed: false, }; }; const getUserDataRecord = () => JSON.parse(localStorage.getItem(localstorageKey)); -const storeData = (data) => { +const storeData = (data: CompleteData) => { const existingData = getUserDataRecord(); localStorage.setItem( localstorageKey, @@ -70,7 +85,17 @@ const storeData = (data) => { ); }; -const stateReducer = (state, message) => { +type Message = + | { kind: 'close' } + | { kind: 'completed' } + | { kind: 'reset' } + | { kind: 'set score'; data: number } + | { kind: 'set comment'; data: string } + | { kind: 'set customer type'; data: CustomerType } + | { kind: 'step forward' } + | { kind: 'step back' }; + +const stateReducer = (state: CompleteData, message: Message) => { switch (message.kind) { case 'close': return { ...state, closedOrCompleted: true }; @@ -104,15 +129,14 @@ const stateReducer = (state, message) => { currentStep: Math.max(state.currentStep - 1, 1), }; } - return state; }; export const FeedbackWrapper = ({ seedData, open }) => { const { siteConfig: { customFields }, } = useDocusaurusContext(); - const feedbackTargetUrl = - customFields?.unleashFeedbackTargetUrl ?? + const feedbackTargetUrl: string | undefined = + (customFields?.unleashFeedbackTargetUrl as string | undefined) ?? (typeof process !== 'undefined' && process?.env?.UNLEASH_FEEDBACK_TARGET_URL); @@ -136,10 +160,11 @@ export const FeedbackWrapper = ({ seedData, open }) => { const stepBack = () => { dispatch({ kind: 'step back' }); }; - const setScore = (score) => dispatch({ kind: 'set score', data: score }); - const setComment = (comment) => + const setScore = (score: number) => + dispatch({ kind: 'set score', data: score }); + const setComment = (comment: string) => dispatch({ kind: 'set comment', data: comment }); - const setCustomerType = (customerType) => + const setCustomerType = (customerType: CustomerType) => dispatch({ kind: 'set customer type', data: customerType }); const submitFeedback = () => { @@ -173,8 +198,9 @@ export const FeedbackWrapper = ({ seedData, open }) => { stepForward(); }; - const visuallyHidden = (stepNumber) => state.currentStep !== stepNumber; - const isHidden = (stepNumber) => + const visuallyHidden = (stepNumber: number) => + state.currentStep !== stepNumber; + const isHidden = (stepNumber: number) => !feedbackIsOpen || visuallyHidden(stepNumber); const Step1 = () => { @@ -273,7 +299,10 @@ export const FeedbackWrapper = ({ seedData, open }) => { const hidden = isHidden(2); const textareaId = 'feedback-comment-input'; const saveComment = () => - setComment(document.getElementById(textareaId).value); + setComment( + (document.getElementById(textareaId) as HTMLTextAreaElement) + .value, + ); return (