Skip to content

Commit

Permalink
Update quick start actions to handle concurrent state updates
Browse files Browse the repository at this point in the history
  • Loading branch information
rohitkrai03 committed Dec 15, 2020
1 parent 8e5b41a commit cfe4536
Show file tree
Hide file tree
Showing 8 changed files with 146 additions and 281 deletions.
Expand Up @@ -17,25 +17,16 @@ const QuickStartController: React.FC<QuickStartControllerProps> = ({ quickStart
const {
activeQuickStartState,
setActiveQuickStart,
setQuickStartStatus,
setQuickStartTaskNumber,
setQuickStartTaskStatus,
nextStep,
previousStep,
} = React.useContext<QuickStartContextValues>(QuickStartContext);
const status = activeQuickStartState?.status as QuickStartStatus;
const taskNumber = activeQuickStartState?.taskNumber as number;
const allTaskStatuses = tasks.map(
(task, index) => activeQuickStartState[`taskStatus${index}`],
) as QuickStartTaskStatus[];
const taskStatus = allTaskStatuses[taskNumber];
const startQuickStart = React.useCallback(
() => setQuickStartStatus(name, QuickStartStatus.IN_PROGRESS),
[name, setQuickStartStatus],
);

const completeQuickStart = React.useCallback(
() => setQuickStartStatus(name, QuickStartStatus.COMPLETE),
[name, setQuickStartStatus],
);

const handleQuickStartChange = React.useCallback(
(quickStartId: string) => setActiveQuickStart(quickStartId),
Expand All @@ -48,48 +39,21 @@ const QuickStartController: React.FC<QuickStartControllerProps> = ({ quickStart
);

const handleNext = React.useCallback(() => {
if (status === QuickStartStatus.NOT_STARTED) startQuickStart();
if (status === QuickStartStatus.COMPLETE && taskNumber === totalTasks)
return handleQuickStartChange('');

if (
status === QuickStartStatus.IN_PROGRESS &&
taskStatus !== QuickStartTaskStatus.INIT &&
taskNumber === totalTasks - 1
)
completeQuickStart();

if (taskStatus === QuickStartTaskStatus.INIT)
return handleTaskStatusChange(QuickStartTaskStatus.REVIEW);

if (taskNumber < totalTasks) return setQuickStartTaskNumber(name, taskNumber + 1);

return null;
}, [
completeQuickStart,
handleQuickStartChange,
handleTaskStatusChange,
name,
setQuickStartTaskNumber,
startQuickStart,
status,
taskNumber,
taskStatus,
totalTasks,
]);
return nextStep(totalTasks);
}, [handleQuickStartChange, nextStep, status, taskNumber, totalTasks]);

const handleBack = React.useCallback(() => {
if (taskNumber > -1) return setQuickStartTaskNumber(name, taskNumber - 1);

return null;
}, [name, setQuickStartTaskNumber, taskNumber]);
return previousStep;
}, [previousStep]);

const handleTaskSelect = React.useCallback(
(selectedTaskNumber: number) => {
setQuickStartTaskNumber(name, selectedTaskNumber);
startQuickStart();
},
[name, setQuickStartTaskNumber, startQuickStart],
[name, setQuickStartTaskNumber],
);

return (
Expand Down
Expand Up @@ -16,36 +16,33 @@ const QuickStartTileFooter: React.FC<QuickStartTileFooterProps> = ({
totalTasks,
}) => {
const { t } = useTranslation();
const {
activeQuickStartID,
setActiveQuickStart,
setQuickStartStatus,
resetQuickStart,
} = React.useContext<QuickStartContextValues>(QuickStartContext);
const startQuickStart = React.useCallback(
const { activeQuickStartID, startQuickStart, restartQuickStart } = React.useContext<
QuickStartContextValues
>(QuickStartContext);

const start = React.useCallback(
(e: React.SyntheticEvent) => {
e.preventDefault();
e.stopPropagation();
if (!activeQuickStartID || activeQuickStartID !== quickStartId)
setActiveQuickStart(quickStartId, totalTasks);
setQuickStartStatus(quickStartId, QuickStartStatus.IN_PROGRESS);
startQuickStart(quickStartId, totalTasks);
},
[activeQuickStartID, quickStartId, setActiveQuickStart, setQuickStartStatus, totalTasks],
[quickStartId, startQuickStart, totalTasks],
);

const restartQuickStart = React.useCallback(
const restart = React.useCallback(
(e: React.SyntheticEvent) => {
resetQuickStart(quickStartId, totalTasks);
startQuickStart(e);
e.preventDefault();
e.stopPropagation();
restartQuickStart(quickStartId, totalTasks);
},
[quickStartId, resetQuickStart, startQuickStart, totalTasks],
[quickStartId, restartQuickStart, totalTasks],
);

return (
<Flex justifyContent={{ default: 'justifyContentSpaceBetween' }}>
{status === QuickStartStatus.NOT_STARTED && (
<FlexItem>
<Button onClick={startQuickStart} variant="link" isInline>
<Button onClick={start} variant="link" isInline>
{t('quickstart~Start the tour')}
</Button>
</FlexItem>
Expand All @@ -59,14 +56,14 @@ const QuickStartTileFooter: React.FC<QuickStartTileFooterProps> = ({
)}
{status === QuickStartStatus.COMPLETE && (
<FlexItem>
<Button onClick={restartQuickStart} variant="link" isInline>
<Button onClick={restart} variant="link" isInline>
{t('quickstart~Start the tour')}
</Button>
</FlexItem>
)}
{status === QuickStartStatus.IN_PROGRESS && (
<FlexItem>
<Button onClick={restartQuickStart} variant="link" isInline>
<Button onClick={restart} variant="link" isInline>
{t('quickstart~Restart the tour')}
</Button>
</FlexItem>
Expand Down
Expand Up @@ -26,9 +26,8 @@ describe('QuickStartTileFooter', () => {
beforeEach(() => {
spyOn(React, 'useContext').and.returnValue({
activeQuickStartID: '',
setActiveQuickStart: () => {},
setQuickStartStatus: () => {},
resetQuickStart: () => {},
startQuickStart: () => {},
restartQuickStart: () => {},
});
});
it('should load proper footer links for completed tours', () => {
Expand Down
@@ -1,2 +1,3 @@
export const QUICKSTART_SEARCH_FILTER_KEY = 'keyword';
export const QUICKSTART_STATUS_FILTER_KEY = 'status';
export const QUICKSTART_REDUX_STATE_LOCAL_STORAGE_KEY = 'bridge/quick-start-redux-state';
@@ -1,6 +1,6 @@
import { createContext, useCallback } from 'react';
import { useUserSettings } from '@console/shared/src/hooks/useUserSettings';
import { QUICK_START_REDUX_STATE_LOCAL_STORAGE_KEY } from '../../../redux/reducers/quick-start-reducer';
import { QUICKSTART_REDUX_STATE_LOCAL_STORAGE_KEY } from './const';
import {
AllQuickStartStates,
QuickStartState,
Expand All @@ -13,23 +13,25 @@ export type QuickStartContextValues = {
allQuickStartStates?: AllQuickStartStates;
activeQuickStartState?: QuickStartState;
setActiveQuickStart?: (quickStartId: string, totalTasks?: number) => void;
setQuickStartStatus?: (quickStartId: string, status: QuickStartStatus) => void;
startQuickStart?: (quickStartId: string, totalTasks: number) => void;
restartQuickStart?: (quickStartId: string, totalTasks: number) => void;
nextStep?: (totalTasks: number) => void;
previousStep?: () => void;
setQuickStartTaskNumber?: (quickStartId: string, taskNumber: number) => void;
setQuickStartTaskStatus?: (taskStatus: QuickStartTaskStatus) => void;
resetQuickStart?: (quickStartId: string, totalTasks: number) => void;
getQuickStartForId?: (id: string) => QuickStartState;
};

export const QuickStartContext = createContext<QuickStartContextValues>({ activeQuickStartID: '' });

const getInitialState = () =>
localStorage.getItem(QUICK_START_REDUX_STATE_LOCAL_STORAGE_KEY)
? JSON.parse(localStorage.getItem(QUICK_START_REDUX_STATE_LOCAL_STORAGE_KEY))
localStorage.getItem(QUICKSTART_REDUX_STATE_LOCAL_STORAGE_KEY)
? JSON.parse(localStorage.getItem(QUICKSTART_REDUX_STATE_LOCAL_STORAGE_KEY))
: {};

const getDefaultQuickStartState = (totalTasks: number) => {
const getDefaultQuickStartState = (totalTasks: number, initialStatus?: QuickStartStatus) => {
const defaultQuickStartState = {
status: QuickStartStatus.NOT_STARTED,
status: initialStatus || QuickStartStatus.NOT_STARTED,
taskNumber: -1,
};
if (totalTasks) {
Expand Down Expand Up @@ -65,26 +67,124 @@ export const useValuesForQuickStartContext = (): QuickStartContextValues => {
[setActiveQuickStartID, setAllQuickStartStates],
);

const setQuickStartStatus = useCallback(
(quickStartId: string, status: QuickStartStatus) => {
const startQuickStart = useCallback(
(quickStartId: string, totalTasks?: number) => {
setActiveQuickStartID((id) => {
if (!id || id !== quickStartId) {
return quickStartId;
}
return id;
});
setAllQuickStartStates((qs) => {
const quickStart = qs[quickStartId];
const updatedQuickStart = { ...quickStart, status };
return { ...qs, [quickStartId]: updatedQuickStart };
if (qs.hasOwnProperty(quickStartId)) {
return {
...qs,
[quickStartId]: { ...qs[quickStartId], status: QuickStartStatus.IN_PROGRESS },
};
}
return {
...qs,
[quickStartId]: getDefaultQuickStartState(totalTasks, QuickStartStatus.IN_PROGRESS),
};
});
},
[setAllQuickStartStates],
[setActiveQuickStartID, setAllQuickStartStates],
);

const restartQuickStart = useCallback(
(quickStartId: string, totalTasks: number) => {
setActiveQuickStartID((id) => {
if (!id || id !== quickStartId) {
return quickStartId;
}
return id;
});
setAllQuickStartStates((qs) => ({
...qs,
[quickStartId]: getDefaultQuickStartState(totalTasks, QuickStartStatus.IN_PROGRESS),
}));
},
[setActiveQuickStartID, setAllQuickStartStates],
);

const nextStep = useCallback(
(totalTasks: number) => {
if (!activeQuickStartID) return;

setAllQuickStartStates((qs) => {
const quickStart = qs[activeQuickStartID];
const status = quickStart?.status;
const taskNumber = quickStart?.taskNumber;
const taskStatus = quickStart[`taskStatus${taskNumber}`];

let updatedStatus;
let updatedTaskNumber;
let updatedTaskStatus;

if (status === QuickStartStatus.NOT_STARTED) {
updatedStatus = QuickStartStatus.IN_PROGRESS;
} else if (
status === QuickStartStatus.IN_PROGRESS &&
taskStatus !== QuickStartTaskStatus.INIT &&
taskNumber === totalTasks - 1
) {
updatedStatus = QuickStartStatus.COMPLETE;
}

if (taskStatus === QuickStartTaskStatus.INIT) {
updatedTaskStatus = QuickStartTaskStatus.REVIEW;
}

if (taskNumber < totalTasks && !updatedTaskStatus) {
updatedTaskNumber = taskNumber + 1;
}

const newState = {
...qs,
[activeQuickStartID]: {
...quickStart,
...(updatedStatus ? { status: updatedStatus } : {}),
...(updatedTaskNumber > -1 ? { taskNumber: updatedTaskNumber } : {}),
...(updatedTaskStatus ? { [`taskStatus${taskNumber}`]: updatedTaskStatus } : {}),
},
};
return newState;
});
},
[activeQuickStartID, setAllQuickStartStates],
);

const previousStep = useCallback(() => {
setAllQuickStartStates((qs) => {
const quickStart = qs[activeQuickStartID];
const taskNumber = quickStart?.taskNumber;

if (taskNumber < 0) return qs;

return { ...qs, [activeQuickStartID]: { ...quickStart, taskNumber: taskNumber - 1 } };
});
}, [activeQuickStartID, setAllQuickStartStates]);

const setQuickStartTaskNumber = useCallback(
(quickStartId: string, taskNumber: number) => {
setAllQuickStartStates((qs) => {
const quickStart = qs[quickStartId];
const updatedQuickStart = { ...quickStart, taskNumber };
const status = quickStart?.status;
let updatedStatus;
if (taskNumber > -1 && status === QuickStartStatus.NOT_STARTED) {
updatedStatus = QuickStartStatus.IN_PROGRESS;
}
const updatedQuickStart = {
...quickStart,
...(updatedStatus ? { status: updatedStatus } : {}),
taskNumber,
};
return { ...qs, [quickStartId]: updatedQuickStart };
});
},
[setAllQuickStartStates],
);

const setQuickStartTaskStatus = useCallback(
(taskStatus: QuickStartTaskStatus) => {
const quickStart = allQuickStartStates[activeQuickStartID];
Expand All @@ -94,28 +194,24 @@ export const useValuesForQuickStartContext = (): QuickStartContextValues => {
},
[allQuickStartStates, activeQuickStartID, setAllQuickStartStates],
);
const resetQuickStart = useCallback(
(quickStartId: string, totalTasks: number) => {
setAllQuickStartStates((qs) => ({
...qs,
[quickStartId]: getDefaultQuickStartState(totalTasks),
}));
},
[setAllQuickStartStates],
);

const activeQuickStartState = allQuickStartStates?.[activeQuickStartID] ?? {};

const getQuickStartForId = useCallback((id: string) => allQuickStartStates[id], [
allQuickStartStates,
]);

return {
activeQuickStartID,
activeQuickStartState,
allQuickStartStates,
setActiveQuickStart,
setQuickStartStatus,
startQuickStart,
restartQuickStart,
nextStep,
previousStep,
setQuickStartTaskNumber,
setQuickStartTaskStatus,
resetQuickStart,
getQuickStartForId,
};
};

0 comments on commit cfe4536

Please sign in to comment.