Skip to content

Commit

Permalink
feat(settings): add required and autosubmit settings
Browse files Browse the repository at this point in the history
misc upgrades
  • Loading branch information
swouf committed May 27, 2024
1 parent 817d190 commit 6cf2b87
Show file tree
Hide file tree
Showing 11 changed files with 557 additions and 1,074 deletions.
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,16 @@
"dependencies": {
"@emotion/react": "11.11.4",
"@emotion/styled": "11.11.5",
"@graasp/apps-query-client": "3.4.4",
"@graasp/sdk": "3.3.0",
"@graasp/ui": "4.17.1",
"@graasp/apps-query-client": "3.4.15",
"@graasp/sdk": "4.12.0",
"@graasp/ui": "github:graasp/graasp-ui#common-comp-survey-apps",
"@mui/icons-material": "5.15.18",
"@mui/lab": "5.0.0-alpha.170",
"@mui/material": "5.15.18",
"@sentry/react": "7.113.0",
"@tanstack/react-query": "4.36.1",
"@tanstack/react-query-devtools": "4.36.1",
"@types/node": "20.12.12",
"@types/react": "18.2.79",
"@types/react-dom": "18.2.25",
"i18next": "23.11.5",
"lodash.isequal": "4.5.0",
Expand All @@ -36,6 +35,7 @@
},
"scripts": {
"dev": "yarn vite",
"dev:mock": "VITE_ENABLE_MOCK_API=true && yarn vite",
"start": "yarn dev",
"start:test": "yarn vite --mode test",
"build": "yarn vite build",
Expand Down
2 changes: 1 addition & 1 deletion public/mockServiceWorker.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
/* tslint:disable */

/**
* Mock Service Worker (1.3.2).
* Mock Service Worker (1.3.3).
* @see https://github.com/mswjs/msw
* - Please do NOT modify this file.
* - Please do NOT serve this file on production.
Expand Down
5 changes: 5 additions & 0 deletions src/config/appSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,8 @@ export type QuestionSettingsType = {
export type AnswerSettings = {
content: string;
};

export type GeneralSettings = {
required: boolean;
autosubmit: boolean;
};
1 change: 1 addition & 0 deletions src/config/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const DEFAULT_LANG = 'en';
6 changes: 5 additions & 1 deletion src/langs/en.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"translations": {
"VERSION": "Version {{version}}",
"ANSWERS": {
"TITLE": "Answers",
"TABLE": {
Expand Down Expand Up @@ -31,7 +32,10 @@
"HELPER_TEXT": "[Optional] If there is one correct answer, then you can include it here and you can automatically see who submitted a correct answer."
},
"GENERAL": {
"TITLE": "General"
"TITLE": "General",
"REQUIRED_SWITCH_LABEL": "Mark the question as required.",
"AUTOSUBMIT_SWITCH_LABEL": "Submit the answer automatically",
"AUTOSUBMIT_MORE_INFO": "If this option is not enabled, the users will have to click on a submit button to send his or her answer."
}
},
"PLAYER": {
Expand Down
29 changes: 11 additions & 18 deletions src/mocks/db.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import type { Database, LocalContext } from '@graasp/apps-query-client';
import {
AppItemFactory,
CompleteMember,
DiscriminatedItem,
ItemType,
MemberFactory,
PermissionLevel,
} from '@graasp/sdk';

Expand All @@ -17,38 +17,31 @@ export const defaultMockContext: LocalContext = {
};

export const mockMembers: CompleteMember[] = [
{
MemberFactory({
id: defaultMockContext.memberId || '',
name: 'current-member',
email: '',
extra: {},
email: 'a@graasp.org',
type: 'individual',
createdAt: new Date('1996-09-08T19:00:00').toISOString(),
updatedAt: new Date().toISOString(),
},
{
}),
MemberFactory({
id: 'mock-member-id-2',
name: 'mock-member-2',
email: '',
extra: {},
email: 'b@graasp.org',
type: 'individual',
createdAt: new Date('1995-02-02T15:00:00').toISOString(),
updatedAt: new Date().toISOString(),
},
}),
];

export const mockItem: DiscriminatedItem = {
export const mockItem = AppItemFactory({
id: defaultMockContext.itemId,
name: 'app-starter-ts-vite',
description: null,
path: '',
settings: {},
type: ItemType.APP,
extra: { [ItemType.APP]: { url: 'http://localhost:3002' } },
name: 'app-short-answer',
creator: mockMembers[0],
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
};
});

const buildDatabase = (members?: CompleteMember[]): Database => ({
appData: [],
Expand Down
12 changes: 11 additions & 1 deletion src/modules/context/SettingsContext.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { FC, ReactElement, createContext, useContext } from 'react';

import { AnswerSettings, QuestionSettingsType } from '@/config/appSettings';
import {
AnswerSettings,
GeneralSettings,
QuestionSettingsType,
} from '@/config/appSettings';
import { hooks, mutations } from '@/config/queryClient';

import Loader from '../common/Loader';
Expand All @@ -10,6 +14,7 @@ import Loader from '../common/Loader';
type AllSettingsType = {
question: QuestionSettingsType;
answer: AnswerSettings;
general: GeneralSettings;
};

// default values for the data property of settings by name
Expand All @@ -20,13 +25,18 @@ const defaultSettingsValues: AllSettingsType = {
answer: {
content: '',
},
general: {
required: false,
autosubmit: false,
},
};

// list of the settings names
const ALL_SETTING_NAMES = [
// name of your settings
'question',
'answer',
'general',
] as const;

// automatically generated types
Expand Down
4 changes: 3 additions & 1 deletion src/modules/main/App.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { useEffect } from 'react';

import { useLocalContext } from '@graasp/apps-query-client';
import { Context, DEFAULT_LANG } from '@graasp/sdk';
import { Context } from '@graasp/sdk';

import { DEFAULT_LANG } from '@/config/constants';

import i18n from '../../config/i18n';
import { SettingsProvider } from '../context/SettingsContext';
Expand Down
69 changes: 69 additions & 0 deletions src/modules/settings/GeneralSettings.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { FC, SyntheticEvent } from 'react';
import { useTranslation } from 'react-i18next';

import InfoIcon from '@mui/icons-material/InfoRounded';
import FormControlLabel from '@mui/material/FormControlLabel';
import Stack from '@mui/material/Stack';
import Switch from '@mui/material/Switch';
import Tooltip from '@mui/material/Tooltip';
import Typography from '@mui/material/Typography';

import { GeneralSettings } from '@/config/appSettings';

const GeneralSettingsEdit: FC<{
general: GeneralSettings;
onChange: (newSetting: GeneralSettings) => void;
}> = ({ general, onChange }) => {
const { t } = useTranslation('translations', {
keyPrefix: 'SETTINGS.GENERAL',
});

const { required, autosubmit } = general;

const handleRequiredChange = (
_event: SyntheticEvent,
checked: boolean,
): void => {
onChange({
...general,
required: checked,
});
};

const handleAutosubmitChange = (
_event: SyntheticEvent,
checked: boolean,
): void => {
onChange({
...general,
autosubmit: checked,
});
};
return (
<Stack spacing={1}>
<Typography variant="h2">{t('TITLE')}</Typography>
<FormControlLabel
control={<Switch />}
label={t('REQUIRED_SWITCH_LABEL')}
checked={required}
onChange={handleRequiredChange}
/>
<FormControlLabel
control={<Switch />}
label={
<>
{t('AUTOSUBMIT_SWITCH_LABEL')}
{/* TODO: Improve this */}
<Tooltip title={t('AUTOSUBMIT_MORE_INFO')}>
<InfoIcon />
</Tooltip>
</>
}
checked={autosubmit}
onChange={handleAutosubmitChange}
/>
</Stack>
);
};

export default GeneralSettingsEdit;
25 changes: 22 additions & 3 deletions src/modules/settings/SettingsView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,28 +9,37 @@ import Typography from '@mui/material/Typography';

import isEqual from 'lodash.isequal';

import { AnswerSettings, QuestionSettingsType } from '@/config/appSettings';
import { version } from '@/../package.json';
import {
AnswerSettings,
GeneralSettings,
QuestionSettingsType,
} from '@/config/appSettings';
import { SETTINGS_SAVE_BTN_CY, SETTINGS_VIEW_CY } from '@/config/selectors';

import { useSettings } from '../context/SettingsContext';
import AnswerSettingsComponent from './AnswersSettings';
import GeneralSettingsEdit from './GeneralSettings';
import QuestionSettingsComponent from './QuestionSettings';

const SettingsView: FC = () => {
const { t } = useTranslation();
const {
question: questionSavedState,
answer: answerSavedState,
general: generalSavedState,
saveSettings,
} = useSettings();

const [question, setQuestion] =
useState<QuestionSettingsType>(questionSavedState);
const [answer, setAnswer] = useState<AnswerSettings>(answerSavedState);
const [general, setGeneral] = useState<GeneralSettings>(generalSavedState);

const saveAllSettings = (): void => {
saveSettings('question', question);
saveSettings('answer', answer);
saveSettings('general', general);
};

useEffect(() => setQuestion(questionSavedState), [questionSavedState]);
Expand All @@ -41,16 +50,26 @@ const SettingsView: FC = () => {
const disableSave = useMemo(() => {
if (
isEqual(questionSavedState, question) &&
isEqual(answerSavedState, answer)
isEqual(answerSavedState, answer) &&
isEqual(generalSavedState, general)
) {
return true;
}
return false;
}, [answer, answerSavedState, question, questionSavedState]);
}, [
answer,
answerSavedState,
general,
generalSavedState,
question,
questionSavedState,
]);

return (
<Stack data-cy={SETTINGS_VIEW_CY} spacing={2}>
<Typography variant="h3">{t('SETTINGS.TITLE')}</Typography>
<Typography variant="caption">{t('VERSION', { version })}</Typography>
<GeneralSettingsEdit general={general} onChange={setGeneral} />
<QuestionSettingsComponent
question={question}
onChange={(newSetting: QuestionSettingsType) => {
Expand Down
Loading

0 comments on commit 6cf2b87

Please sign in to comment.