diff --git a/frontend/src/editor/Checklist/index.tsx b/frontend/src/editor/Checklist/index.tsx index 9763ae5294b004f697a55b9b5e2ede85cc128fc8..b172db12f8aab14bcfdb903079a5201c464cbbdc 100644 --- a/frontend/src/editor/Checklist/index.tsx +++ b/frontend/src/editor/Checklist/index.tsx @@ -1,8 +1,9 @@ import { CheckboxCard, Classes } from '@blueprintjs/core' import { memo, useEffect, useState, type FC } from 'react' +import { Checklist } from '../types' interface ChecklistProps { - conditions: { name: string; description: string }[] + conditions: Checklist initChecked: boolean[] onInputChange: (conditions: boolean[]) => void } diff --git a/frontend/src/editor/ConclusionForm/index.tsx b/frontend/src/editor/ConclusionForm/index.tsx index 29088f83f56d06247d7f2101bb33386907286754..6b0c6116334a75258704f10ef41b592f9d4875c1 100644 --- a/frontend/src/editor/ConclusionForm/index.tsx +++ b/frontend/src/editor/ConclusionForm/index.tsx @@ -1,7 +1,7 @@ import Checklist from '@/editor/Checklist' import useEditorStorage from '@/editor/useEditorStorage' import { memo, useEffect, useState } from 'react' -import { CONCLUSION_CONDITIONS } from '../utils' +import { CONCLUSION_CONDITIONS } from '../assets/pageContent/conclusion' const ConclusionForm = () => { const [config, setConfig] = useEditorStorage() diff --git a/frontend/src/editor/EditorPage/index.tsx b/frontend/src/editor/EditorPage/index.tsx index 3f5faa17a1329cfed9fed0528ba820c5e5463c1c..9beeaf919e287279b1b800d3823b27bf12ebab6c 100644 --- a/frontend/src/editor/EditorPage/index.tsx +++ b/frontend/src/editor/EditorPage/index.tsx @@ -4,6 +4,9 @@ import { Button } from '@blueprintjs/core' import { css } from '@emotion/css' import type { FC, ReactNode } from 'react' import { memo } from 'react' +import FaqSection from '../FaqSection' +import { PAGE_INFORMATION } from '../assets/pageInformation' +import type { PageNames } from '../types' const editorPage = css` display: grid; @@ -13,8 +16,7 @@ const editorPage = css` ` interface EditorPageProps { - title: string - description: string + pageKey: PageNames children: ReactNode prevPath: Path nextPath?: Path @@ -24,8 +26,7 @@ interface EditorPageProps { } const EditorPage: FC<EditorPageProps> = ({ - title, - description, + pageKey, children, prevPath, nextPath, @@ -34,6 +35,7 @@ const EditorPage: FC<EditorPageProps> = ({ pageVisible, }) => { const nav = useNavigate() + const content = PAGE_INFORMATION[pageKey] if (!pageVisible) { nav('/editor') @@ -41,9 +43,19 @@ const EditorPage: FC<EditorPageProps> = ({ return ( <div className={editorPage}> - <h1>{title}</h1> - <p style={{ marginBottom: '1rem' }}>{description}</p> - <div style={{ overflowY: 'auto' }}>{children}</div> + <h1>{content.title}</h1> + <p + dangerouslySetInnerHTML={{ + __html: content.description, + }} + style={{ marginBottom: '1rem' }} + /> + <div style={{ overflowY: 'auto' }}> + {children} + {content.faq && content.faq.length > 0 && ( + <FaqSection questions={content.faq} /> + )} + </div> <div style={{ display: 'flex', diff --git a/frontend/src/editor/EmailAddressForm/index.tsx b/frontend/src/editor/EmailAddressForm/index.tsx index 35cc8d43c88b85408b4b7152a2047e77720d6a98..e63156200070277a088196804d1ccd9e4a101b79 100644 --- a/frontend/src/editor/EmailAddressForm/index.tsx +++ b/frontend/src/editor/EmailAddressForm/index.tsx @@ -5,16 +5,17 @@ import { import type { ButtonProps } from '@blueprintjs/core' import { Button, - Checkbox, Dialog, DialogBody, DialogFooter, InputGroup, - Label, } from '@blueprintjs/core' import { useNotifyContext } from '@inject/shared/notification/contexts/NotifyContext' import type { FC } from 'react' import { memo, useCallback, useEffect, useState } from 'react' +import TooltipCheckbox from '../Tooltips/TooltipCheckbox' +import TooltipLabel from '../Tooltips/TooltipLabel' +import { EMAIL_ADDRESS_FORM } from '../assets/pageContent/emails' import type { EmailAddressInfo } from '../indexeddb/types' interface EmailAddressFormProps { @@ -96,34 +97,33 @@ const EmailAddressForm: FC<EmailAddressFormProps> = ({ title={emailAddressInfo ? 'Edit email address' : 'New email address'} > <DialogBody> - <Label> - Address + <TooltipLabel label={EMAIL_ADDRESS_FORM.address}> <InputGroup placeholder='Input text' value={address} onChange={e => setAddress(e.target.value)} /> - </Label> - <Label> - Organization + </TooltipLabel> + <TooltipLabel label={EMAIL_ADDRESS_FORM.organization}> <InputGroup placeholder='Input text' value={organization} onChange={e => setOrganization(e.target.value)} /> - </Label> - <Label> - Description + </TooltipLabel> + <TooltipLabel label={EMAIL_ADDRESS_FORM.description}> <InputGroup placeholder='Input text' value={description} onChange={e => setDescription(e.target.value)} /> - </Label> - <Checkbox - label='Team visible' - checked={teamVisible} - onChange={e => setTeamVisible(e.target.checked)} + </TooltipLabel> + <TooltipCheckbox + label={EMAIL_ADDRESS_FORM.teamVisible} + checkboxProps={{ + checked: teamVisible, + onChange: () => setTeamVisible(!teamVisible), + }} /> </DialogBody> <DialogFooter diff --git a/frontend/src/editor/EmailAddressSelector/index.tsx b/frontend/src/editor/EmailAddressSelector/index.tsx index 5c9e53c9f26e5cb8102478cb6b34136bf8494082..2311f3a92061dc45321dd0bc74e52ebb4b6bb653 100644 --- a/frontend/src/editor/EmailAddressSelector/index.tsx +++ b/frontend/src/editor/EmailAddressSelector/index.tsx @@ -1,17 +1,21 @@ import type { OptionProps } from '@blueprintjs/core' -import { HTMLSelect, Label } from '@blueprintjs/core' +import { HTMLSelect } from '@blueprintjs/core' import { useLiveQuery } from 'dexie-react-hooks' import { memo, useEffect, useMemo, type FC } from 'react' import EmailAddressForm from '../EmailAddressForm' +import TooltipLabel from '../Tooltips/TooltipLabel' import { db } from '../indexeddb/db' import type { EmailAddressInfo } from '../indexeddb/types' +import type { ExtendedLabel } from '../types' -interface EmailAddressFormProps { +interface EmailAddressSelectorProps { + label: ExtendedLabel emailAddressId: number onChange: (id: number) => void } -const EmailAddressSelector: FC<EmailAddressFormProps> = ({ +const EmailAddressSelector: FC<EmailAddressSelectorProps> = ({ + label, emailAddressId, onChange, }) => { @@ -42,14 +46,13 @@ const EmailAddressSelector: FC<EmailAddressFormProps> = ({ return ( <div style={{ display: 'flex', width: '100%' }}> - <Label style={{ flexGrow: '1' }}> - Address + <TooltipLabel label={label} style={{ flexGrow: '1' }}> <HTMLSelect options={emailAddressOptions} value={emailAddressId} onChange={event => onChange(Number(event.currentTarget.value))} /> - </Label> + </TooltipLabel> <EmailAddressForm buttonProps={{ minimal: true, diff --git a/frontend/src/editor/EmailTemplateFormContent/index.tsx b/frontend/src/editor/EmailTemplateFormContent/index.tsx index aed6d96a839d6b1cf4cd55e8d1dbce06754ce32f..dac76313af498341a639e264674f22b2d7458853 100644 --- a/frontend/src/editor/EmailTemplateFormContent/index.tsx +++ b/frontend/src/editor/EmailTemplateFormContent/index.tsx @@ -1,7 +1,9 @@ -import { InputGroup, Label, TextArea } from '@blueprintjs/core' +import { InputGroup, TextArea } from '@blueprintjs/core' import { memo, type FC } from 'react' import EmailAddressSelector from '../EmailAddressSelector' import FileSelector from '../FileSelector' +import TooltipLabel from '../Tooltips/TooltipLabel' +import { EMAIL_TEMPLATE_FORM } from '../assets/pageContent/emails' interface EmailTemplateFormProps { context: string @@ -26,19 +28,18 @@ const EmailTemplateForm: FC<EmailTemplateFormProps> = ({ }) => ( <div> <EmailAddressSelector + label={EMAIL_TEMPLATE_FORM.address} emailAddressId={emailAddressId} onChange={id => onEmailAddressIdChange(id)} /> - <Label> - Context + <TooltipLabel label={EMAIL_TEMPLATE_FORM.context}> <InputGroup placeholder='Input text' value={context} onChange={e => onContextChange(e.target.value)} /> - </Label> - <Label> - Content + </TooltipLabel> + <TooltipLabel label={EMAIL_TEMPLATE_FORM.content}> <TextArea value={content} style={{ @@ -50,8 +51,12 @@ const EmailTemplateForm: FC<EmailTemplateFormProps> = ({ placeholder='Input text' onChange={e => onContentChange(e.target.value)} /> - </Label> - <FileSelector fileId={fileId} onChange={id => onFileIdChange(id)} /> + </TooltipLabel> + <FileSelector + label={EMAIL_TEMPLATE_FORM.file} + fileId={fileId} + onChange={id => onFileIdChange(id)} + /> </div> ) diff --git a/frontend/src/editor/ExerciseInformationForm/index.tsx b/frontend/src/editor/ExerciseInformationForm/index.tsx index c080156cf9a6c911200e81b0e07fc136e68ff763..84607ead94ac3b36dd66199ce631345338ba2d73 100644 --- a/frontend/src/editor/ExerciseInformationForm/index.tsx +++ b/frontend/src/editor/ExerciseInformationForm/index.tsx @@ -1,6 +1,8 @@ import useEditorStorage from '@/editor/useEditorStorage' -import { InputGroup, Label, TextArea } from '@blueprintjs/core' +import { InputGroup, TextArea } from '@blueprintjs/core' import { memo, useEffect, useState } from 'react' +import TooltipLabel from '../Tooltips/TooltipLabel' +import { EXERCISE_INFORMATION_FORM } from '../assets/pageContent/exerciseInformation' const ExerciseInformationForm = () => { const [config, setConfig] = useEditorStorage() @@ -19,16 +21,14 @@ const ExerciseInformationForm = () => { return ( <div> - <Label> - Name + <TooltipLabel label={EXERCISE_INFORMATION_FORM.name}> <InputGroup placeholder='Input text' value={name} onChange={e => setName(e.target.value)} /> - </Label> - <Label> - Description + </TooltipLabel> + <TooltipLabel label={EXERCISE_INFORMATION_FORM.description}> <TextArea value={description} style={{ @@ -40,15 +40,14 @@ const ExerciseInformationForm = () => { placeholder='Input text' onChange={e => setDescription(e.target.value)} /> - </Label> - <Label> - Who is your trainee? + </TooltipLabel> + <TooltipLabel label={EXERCISE_INFORMATION_FORM.trainee}> <InputGroup placeholder='Input text' value={trainee} onChange={e => setTrainee(e.target.value)} /> - </Label> + </TooltipLabel> </div> ) } diff --git a/frontend/src/editor/ExpressionBuilder/index.tsx b/frontend/src/editor/ExpressionBuilder/index.tsx index f06ef1f96a0b50140b0257ddb245b8d01d4ae7f1..24e017b354bf2444420131cdeeae6aab65b19eae 100644 --- a/frontend/src/editor/ExpressionBuilder/index.tsx +++ b/frontend/src/editor/ExpressionBuilder/index.tsx @@ -4,7 +4,9 @@ import { css } from '@emotion/css' import { useLiveQuery } from 'dexie-react-hooks' import { isEqual } from 'lodash' import { memo, useCallback, useEffect, useMemo, useState, type FC } from 'react' +import TooltipLabel from '../Tooltips/TooltipLabel' import { getMilestonesWithNames } from '../indexeddb/joins' +import type { ExtendedLabel } from '../types' import { CLOSING_BRACKET, DEFAULT_OPTION, @@ -20,7 +22,7 @@ import useValidateExpression from './useValidateExpression' const condition = css` display: flex; align-items: start; - margin-bottom: 1rem; + margin: 0.5rem 0 1rem; ` const expressionArea = css` @@ -43,11 +45,13 @@ const errorMessage = css` ` interface ExpressionBuilderProps { + label: ExtendedLabel initExpression?: number[] onExpressionChange: (value: number[]) => void } const ExpressionBuilder: FC<ExpressionBuilderProps> = ({ + label, initExpression, onExpressionChange, }) => { @@ -159,55 +163,56 @@ const ExpressionBuilder: FC<ExpressionBuilderProps> = ({ return ( <div style={{ marginBottom: '1rem' }}> - <p>Condition</p> - <div className={condition}> - <Callout - className={expressionArea} - icon={null} - intent={isValid ? 'none' : 'danger'} - > - {expression.map((block, index) => ( - <ExpressionBlock - key={index} - variables={variables} - block={block} - onRemove={() => removeBlock(index)} - onModify={newBlock => modifyBlock(index, newBlock)} - /> - ))} - <div className={nextBlock}> - <HTMLSelect - options={[DEFAULT_OPTION, ...options]} - value={option.value} - onChange={event => { - const selectedOption = event.currentTarget.selectedOptions[0] - addBlock({ - value: selectedOption.value, - label: selectedOption.label, - }) + <TooltipLabel label={label}> + <div className={condition}> + <Callout + className={expressionArea} + icon={null} + intent={isValid ? 'none' : 'danger'} + > + {expression.map((block, index) => ( + <ExpressionBlock + key={index} + variables={variables} + block={block} + onRemove={() => removeBlock(index)} + onModify={newBlock => modifyBlock(index, newBlock)} + /> + ))} + <div className={nextBlock}> + <HTMLSelect + options={[DEFAULT_OPTION, ...options]} + value={option.value} + onChange={event => { + const selectedOption = event.currentTarget.selectedOptions[0] + addBlock({ + value: selectedOption.value, + label: selectedOption.label, + }) + }} + /> + </div> + </Callout> + <Button + onClick={clearExpression} + disabled={expression.length === 0} + icon='trash' + text='Clear' + /> + </div> + {error && ( + <div className={errorMessage}> + <Icon + icon='error' + intent='danger' + style={{ + marginRight: '0.5rem', }} /> + {error} </div> - </Callout> - <Button - onClick={clearExpression} - disabled={expression.length === 0} - icon='trash' - text='Clear' - /> - </div> - {error && ( - <div className={errorMessage}> - <Icon - icon='error' - intent='danger' - style={{ - marginRight: '0.5rem', - }} - /> - {error} - </div> - )} + )} + </TooltipLabel> </div> ) } diff --git a/frontend/src/editor/FaqSection/index.tsx b/frontend/src/editor/FaqSection/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..4855772a923599a6d075567712650c8d43ef5378 --- /dev/null +++ b/frontend/src/editor/FaqSection/index.tsx @@ -0,0 +1,32 @@ +import { Section, SectionCard } from '@blueprintjs/core' +import type { FC } from 'react' +import { memo } from 'react' +import type { FAQQuestion } from '../types' + +interface FaqSectionProps { + questions: FAQQuestion[] +} + +const FaqSection: FC<FaqSectionProps> = ({ questions }) => ( + <div style={{ marginTop: '3rem' }}> + <h2>FAQ</h2> + {questions.map((question, i) => ( + <Section + key={i} + collapsible + collapseProps={{ defaultIsOpen: false }} + title={question.question} + > + <SectionCard> + <div + dangerouslySetInnerHTML={{ + __html: question.answer, + }} + /> + </SectionCard> + </Section> + ))} + </div> +) + +export default memo(FaqSection) diff --git a/frontend/src/editor/FileSelector/index.tsx b/frontend/src/editor/FileSelector/index.tsx index 67e6195ea73459edacb1ab956cc19c7c8b8343f4..54679074ad7cf18861c91539043494ac56581be4 100644 --- a/frontend/src/editor/FileSelector/index.tsx +++ b/frontend/src/editor/FileSelector/index.tsx @@ -1,18 +1,21 @@ import type { OptionProps } from '@blueprintjs/core' -import { HTMLSelect, Label } from '@blueprintjs/core' +import { HTMLSelect } from '@blueprintjs/core' import { useLiveQuery } from 'dexie-react-hooks' import type { FC } from 'react' import { useEffect, useMemo } from 'react' import FileUploader from '../FileUploader' +import TooltipLabel from '../Tooltips/TooltipLabel' import { db } from '../indexeddb/db' import type { ContentFile } from '../indexeddb/types' +import type { ExtendedLabel } from '../types' interface FileSelectorProps { + label: ExtendedLabel fileId: number onChange: (id: number) => void } -const FileSelector: FC<FileSelectorProps> = ({ fileId, onChange }) => { +const FileSelector: FC<FileSelectorProps> = ({ label, fileId, onChange }) => { const files = useLiveQuery(() => db.files.toArray(), [], []) const fileOptions: OptionProps[] = useMemo(() => { @@ -43,14 +46,13 @@ const FileSelector: FC<FileSelectorProps> = ({ fileId, onChange }) => { return ( <div style={{ display: 'flex', width: '100%' }}> - <Label style={{ flexGrow: '1' }}> - File + <TooltipLabel label={label} style={{ flexGrow: '1' }}> <HTMLSelect options={fileOptions} value={fileId} onChange={event => onChange(Number(event.currentTarget.value))} /> - </Label> + </TooltipLabel> <FileUploader buttonProps={{ minimal: true, diff --git a/frontend/src/editor/FileUploader/index.tsx b/frontend/src/editor/FileUploader/index.tsx index 86645bc5bac2048772c266c91468880394469705..44d27b4dd6b3a0a05a04bd69cb00f08cb26b46c5 100644 --- a/frontend/src/editor/FileUploader/index.tsx +++ b/frontend/src/editor/FileUploader/index.tsx @@ -7,11 +7,12 @@ import { DialogFooter, FileInput, InputGroup, - Label, } from '@blueprintjs/core' import { useNotifyContext } from '@inject/shared/notification/contexts/NotifyContext' import type { ChangeEvent, FC } from 'react' import { useCallback, useEffect, useMemo, useState } from 'react' +import TooltipLabel from '../Tooltips/TooltipLabel' +import { FILE_UPLOAD_FORM } from '../assets/pageContent/files' import { addFile, updateFile } from '../indexeddb/operations' import type { ContentFile } from '../indexeddb/types' @@ -93,16 +94,14 @@ const FileUploader: FC<FileUploaderProps> = ({ title={contentFile ? 'Edit file' : 'New file'} > <DialogBody> - <Label> - Name + <TooltipLabel label={FILE_UPLOAD_FORM.name}> <InputGroup placeholder={placeholder} value={name} onChange={e => setName(e.target.value)} /> - </Label> - <Label> - File + </TooltipLabel> + <TooltipLabel label={FILE_UPLOAD_FORM.file}> <div style={{ display: 'flex', gap: '0.5rem', alignItems: 'flex-end' }} > @@ -114,7 +113,7 @@ const FileUploader: FC<FileUploaderProps> = ({ onInputChange={handleFileChange} /> </div> - </Label> + </TooltipLabel> </DialogBody> <DialogFooter actions={ diff --git a/frontend/src/editor/FinalInformationForm/EmailChannelForm.tsx b/frontend/src/editor/FinalInformationForm/EmailChannelForm.tsx index 4893d136a3c83c50c9834b52564a9f021515bc41..33214cc254f5c4eb4ffac972708828ec0ac6e681 100644 --- a/frontend/src/editor/FinalInformationForm/EmailChannelForm.tsx +++ b/frontend/src/editor/FinalInformationForm/EmailChannelForm.tsx @@ -1,11 +1,8 @@ -import { - Checkbox, - InputGroup, - Label, - Section, - SectionCard, -} from '@blueprintjs/core' +import { InputGroup, Section, SectionCard } from '@blueprintjs/core' import { memo, type FC } from 'react' +import TooltipCheckbox from '../Tooltips/TooltipCheckbox' +import TooltipLabel from '../Tooltips/TooltipLabel' +import { EMAIL_CHANNEL_FORM } from '../assets/pageContent/finalInformation' interface EmailChannelFormProps { emailChannelName: string @@ -24,30 +21,30 @@ const EmailChannelForm: FC<EmailChannelFormProps> = ({ customEmailSuffix, onCustomEmailSuffixChange, }) => ( - <Section title='Email'> + <Section title='Email' style={{ marginBottom: '1rem' }}> <SectionCard> - <Label> - Custom email channel name + <TooltipLabel label={EMAIL_CHANNEL_FORM.name}> <InputGroup placeholder='Input text' value={emailChannelName} onChange={e => onEmailChannelNameChange(e.target.value)} /> - </Label> - <Checkbox - checked={emailBetweenTeams} - onChange={() => onEmailBetweenTeamsChange(!emailBetweenTeams)} - label={'Enable emails between teams'} + </TooltipLabel> + <TooltipCheckbox + label={EMAIL_CHANNEL_FORM.emailsBetweenTeams} + checkboxProps={{ + checked: emailBetweenTeams, + onChange: () => onEmailBetweenTeamsChange(!emailBetweenTeams), + }} /> {emailBetweenTeams && ( - <Label> - Custom email suffix + <TooltipLabel label={EMAIL_CHANNEL_FORM.suffix}> <InputGroup placeholder='Input text' value={customEmailSuffix} onChange={e => onCustomEmailSuffixChange(e.target.value)} /> - </Label> + </TooltipLabel> )} </SectionCard> </Section> diff --git a/frontend/src/editor/FinalInformationForm/ExerciseDurationForm.tsx b/frontend/src/editor/FinalInformationForm/ExerciseDurationForm.tsx index 97f91e54286b58ee6fbdd933f2d330d56b12fbb2..5afa468795b82a01c66e56e74855e7d51e707c0a 100644 --- a/frontend/src/editor/FinalInformationForm/ExerciseDurationForm.tsx +++ b/frontend/src/editor/FinalInformationForm/ExerciseDurationForm.tsx @@ -1,5 +1,8 @@ -import { Checkbox, Label, NumericInput } from '@blueprintjs/core' +import { NumericInput } from '@blueprintjs/core' import { memo, type FC } from 'react' +import TooltipCheckbox from '../Tooltips/TooltipCheckbox' +import TooltipLabel from '../Tooltips/TooltipLabel' +import { EXERCISE_DURATION_FORM } from '../assets/pageContent/finalInformation' interface ExerciseDurationFormProps { exerciseDuration: number @@ -15,18 +18,19 @@ const ExerciseDurationForm: FC<ExerciseDurationFormProps> = ({ onShowExerciseTimeChange, }) => ( <div> - <Label> - Exercise duration in minutes + <TooltipLabel label={EXERCISE_DURATION_FORM.exerciseDuration}> <NumericInput placeholder='Input number' value={exerciseDuration} onValueChange={(value: number) => onExerciseDurationChange(value)} /> - </Label> - <Checkbox - checked={showExerciseTime} - onChange={() => onShowExerciseTimeChange(!showExerciseTime)} - label={'Show exercise time to trainees?'} + </TooltipLabel> + <TooltipCheckbox + label={EXERCISE_DURATION_FORM.showTime} + checkboxProps={{ + checked: showExerciseTime, + onChange: () => onShowExerciseTimeChange(!showExerciseTime), + }} /> </div> ) diff --git a/frontend/src/editor/FinalInformationForm/FinalMilestoneForm.tsx b/frontend/src/editor/FinalInformationForm/FinalMilestoneForm.tsx index 326a544a618f8d5026cdded4365502bbf9eee826..5348f3348fecd5636a1539f3dab78cd0f7cf3ef2 100644 --- a/frontend/src/editor/FinalInformationForm/FinalMilestoneForm.tsx +++ b/frontend/src/editor/FinalInformationForm/FinalMilestoneForm.tsx @@ -1,7 +1,9 @@ import type { OptionProps } from '@blueprintjs/core' -import { HTMLSelect, Label } from '@blueprintjs/core' +import { HTMLSelect } from '@blueprintjs/core' import { useLiveQuery } from 'dexie-react-hooks' import { memo, useEffect, useMemo, type FC } from 'react' +import TooltipLabel from '../Tooltips/TooltipLabel' +import { FINAL_MILESTONE_FORM } from '../assets/pageContent/finalInformation' import { getMilestonesWithNames } from '../indexeddb/joins' import { getVariables } from '../utils' @@ -37,8 +39,7 @@ const FinalMilestoneForm: FC<FinalMilestoneFormProps> = ({ }, [finalMilestone, milestones]) return ( - <Label> - Final milestone + <TooltipLabel label={FINAL_MILESTONE_FORM.finalMilestone}> <HTMLSelect options={options} value={finalMilestone} @@ -46,7 +47,7 @@ const FinalMilestoneForm: FC<FinalMilestoneFormProps> = ({ onFinalMilestoneChange(Number(event.currentTarget.value)) } /> - </Label> + </TooltipLabel> ) } diff --git a/frontend/src/editor/FinalInformationForm/FormChannelForm.tsx b/frontend/src/editor/FinalInformationForm/FormChannelForm.tsx index 30c44542b56b3e27fa6a0281ebce40de44f5dc57..eb9942cfb56249b300a143fab3c25835e715a420 100644 --- a/frontend/src/editor/FinalInformationForm/FormChannelForm.tsx +++ b/frontend/src/editor/FinalInformationForm/FormChannelForm.tsx @@ -1,5 +1,7 @@ -import { InputGroup, Label, Section, SectionCard } from '@blueprintjs/core' +import { InputGroup, Section, SectionCard } from '@blueprintjs/core' import { memo, type FC } from 'react' +import TooltipLabel from '../Tooltips/TooltipLabel' +import { QUESTIONNAIRE_CHANNEL_FORM } from '../assets/pageContent/finalInformation' interface FormChannelFormProps { formChannelName: string @@ -10,16 +12,15 @@ const FormChannelForm: FC<FormChannelFormProps> = ({ formChannelName, onFormChannelNameChange, }) => ( - <Section title='Form' style={{ marginBottom: '1rem' }}> + <Section title='Form'> <SectionCard> - <Label> - Custom form channel name + <TooltipLabel label={QUESTIONNAIRE_CHANNEL_FORM.name}> <InputGroup placeholder='Input text' value={formChannelName} onChange={e => onFormChannelNameChange(e.target.value)} /> - </Label> + </TooltipLabel> </SectionCard> </Section> ) diff --git a/frontend/src/editor/FinalInformationForm/InfoChannelForm.tsx b/frontend/src/editor/FinalInformationForm/InfoChannelForm.tsx index 34f34d6ed7a646715e853cd6c046b6c9e1b8fc86..9c4b3a229d883723379b176d76f4196f94be8014 100644 --- a/frontend/src/editor/FinalInformationForm/InfoChannelForm.tsx +++ b/frontend/src/editor/FinalInformationForm/InfoChannelForm.tsx @@ -1,5 +1,7 @@ -import { InputGroup, Label, Section, SectionCard } from '@blueprintjs/core' +import { InputGroup, Section, SectionCard } from '@blueprintjs/core' import { memo, type FC } from 'react' +import TooltipLabel from '../Tooltips/TooltipLabel' +import { INFORMATION_CHANNEL_FORM } from '../assets/pageContent/finalInformation' interface InfoChannelFormProps { infoChannelName: string @@ -12,14 +14,13 @@ const InfoChannelForm: FC<InfoChannelFormProps> = ({ }) => ( <Section title='Information' style={{ marginBottom: '1rem' }}> <SectionCard> - <Label> - Custom information channel name + <TooltipLabel label={INFORMATION_CHANNEL_FORM.name}> <InputGroup placeholder='Input text' value={infoChannelName} onChange={e => onInfoChannelNameChange(e.target.value)} /> - </Label> + </TooltipLabel> </SectionCard> </Section> ) diff --git a/frontend/src/editor/FinalInformationForm/ToolChannelForm.tsx b/frontend/src/editor/FinalInformationForm/ToolChannelForm.tsx index df6b8fbb536ba20ba2ac96b7437d21418265383d..e85280706643ea2197d0f0c723e2773a948a7802 100644 --- a/frontend/src/editor/FinalInformationForm/ToolChannelForm.tsx +++ b/frontend/src/editor/FinalInformationForm/ToolChannelForm.tsx @@ -1,5 +1,7 @@ -import { InputGroup, Label, Section, SectionCard } from '@blueprintjs/core' +import { InputGroup, Section, SectionCard } from '@blueprintjs/core' import { memo, type FC } from 'react' +import TooltipLabel from '../Tooltips/TooltipLabel' +import { TOOL_CHANNEL_FORM } from '../assets/pageContent/finalInformation' interface ToolChannelFormProps { toolChannelName: string @@ -12,14 +14,13 @@ const ToolChannelForm: FC<ToolChannelFormProps> = ({ }) => ( <Section title='Tools' style={{ marginBottom: '1rem' }}> <SectionCard> - <Label> - Custom tool channel name + <TooltipLabel label={TOOL_CHANNEL_FORM.name}> <InputGroup placeholder='Input text' value={toolChannelName} onChange={e => onToolChannelNameChange(e.target.value)} /> - </Label> + </TooltipLabel> </SectionCard> </Section> ) diff --git a/frontend/src/editor/InjectForm/index.tsx b/frontend/src/editor/InjectForm/index.tsx index b6b79f501c41f7a9261eb3b44bb61726d5a99386..3ef93c7052383860095631a78bee1b14bd9db3a2 100644 --- a/frontend/src/editor/InjectForm/index.tsx +++ b/frontend/src/editor/InjectForm/index.tsx @@ -6,12 +6,13 @@ import { DialogFooter, HTMLSelect, InputGroup, - Label, TextArea, } from '@blueprintjs/core' import { useNotifyContext } from '@inject/shared/notification/contexts/NotifyContext' import type { FC } from 'react' import { memo, useCallback, useEffect, useState } from 'react' +import TooltipLabel from '../Tooltips/TooltipLabel' +import { INJECT_FORM } from '../assets/pageContent/injects' import { addInjectInfo, updateInjectInfo } from '../indexeddb/operations' import type { InjectInfo } from '../indexeddb/types' import { InjectType } from '../indexeddb/types' @@ -80,16 +81,14 @@ const InjectForm: FC<InjectFormProps> = ({ inject, buttonProps }) => { title={inject ? 'Edit inject' : 'New inject'} > <DialogBody> - <Label> - Title + <TooltipLabel label={INJECT_FORM.name}> <InputGroup placeholder='Input text' value={name} onChange={e => setName(e.target.value)} /> - </Label> - <Label> - What is this inject about? (optional) + </TooltipLabel> + <TooltipLabel label={INJECT_FORM.description}> <TextArea value={description} style={{ @@ -101,9 +100,8 @@ const InjectForm: FC<InjectFormProps> = ({ inject, buttonProps }) => { placeholder='Input text' onChange={e => setDescription(e.target.value)} /> - </Label> - <Label> - Channel + </TooltipLabel> + <TooltipLabel label={INJECT_FORM.channel}> <HTMLSelect options={INJECT_TYPES} value={type} @@ -111,7 +109,7 @@ const InjectForm: FC<InjectFormProps> = ({ inject, buttonProps }) => { setType(event.currentTarget.value as InjectType) } /> - </Label> + </TooltipLabel> </DialogBody> <DialogFooter actions={ diff --git a/frontend/src/editor/InjectSpecification/ConnectionsForm.tsx b/frontend/src/editor/InjectSpecification/ConnectionsForm.tsx index 39214a2815c8ce537f0167aee5357e35c2fb8fcb..f1a6494a0cb3b352c8c7a5e342d0599286d2ec9a 100644 --- a/frontend/src/editor/InjectSpecification/ConnectionsForm.tsx +++ b/frontend/src/editor/InjectSpecification/ConnectionsForm.tsx @@ -1,9 +1,11 @@ -import { Button, Label, NumericInput } from '@blueprintjs/core' +import { Button, NumericInput } from '@blueprintjs/core' import { useNotifyContext } from '@inject/shared/notification/contexts/NotifyContext' import { useLiveQuery } from 'dexie-react-hooks' import { memo, useCallback, useEffect, useState, type FC } from 'react' import ExpressionBuilder from '../ExpressionBuilder' import useValidateExpression from '../ExpressionBuilder/useValidateExpression' +import TooltipLabel from '../Tooltips/TooltipLabel' +import { INJECT_CONNECTIONS_FORM } from '../assets/pageContent/injectSpecification' import { addInjectControl, getInjectControlByInjectInfoId, @@ -64,27 +66,26 @@ const ConnectionsForm: FC<ConnectionsFormProps> = ({ return ( <div> - <Label> - Start + <TooltipLabel label={INJECT_CONNECTIONS_FORM.time}> <NumericInput placeholder='Input number' min={0} value={start} onValueChange={(value: number) => setStart(value)} /> - </Label> + </TooltipLabel> {injectType !== InjectType.QUESTIONNAIRE && ( - <Label> - Delay + <TooltipLabel label={INJECT_CONNECTIONS_FORM.delay}> <NumericInput placeholder='Input number' min={0} value={delay} onValueChange={(value: number) => setDelay(value)} /> - </Label> + </TooltipLabel> )} <ExpressionBuilder + label={INJECT_CONNECTIONS_FORM.condition} initExpression={injectControl?.milestoneCondition} onExpressionChange={expression => setMilestoneCondition(expression)} /> diff --git a/frontend/src/editor/InjectSpecification/EmailInjectForm.tsx b/frontend/src/editor/InjectSpecification/EmailInjectForm.tsx index 47bf4da2afc149ebfe250a8566b65ea7ae088c26..90d9f5a162feb14bbf435cb0ff0db00076190e0e 100644 --- a/frontend/src/editor/InjectSpecification/EmailInjectForm.tsx +++ b/frontend/src/editor/InjectSpecification/EmailInjectForm.tsx @@ -1,15 +1,12 @@ -import { - Button, - InputGroup, - Label, - NumericInput, - TextArea, -} from '@blueprintjs/core' +import { Button, InputGroup, NumericInput, TextArea } from '@blueprintjs/core' import { useNotifyContext } from '@inject/shared/notification/contexts/NotifyContext' import { useLiveQuery } from 'dexie-react-hooks' import { memo, useCallback, useEffect, useState, type FC } from 'react' import EmailAddressSelector from '../EmailAddressSelector' import FileSelector from '../FileSelector' +import TooltipLabel from '../Tooltips/TooltipLabel' +import { EMAIL_ADDRESS_FORM } from '../assets/pageContent/emails' +import { EMAIL_INJECT_FORM } from '../assets/pageContent/injectSpecification' import { addEmailInject, getEmailInjectByInjectInfoId, @@ -64,19 +61,18 @@ const EmailInjectForm: FC<EmailInjectFormProps> = ({ injectInfoId }) => { return ( <div> <EmailAddressSelector + label={EMAIL_ADDRESS_FORM.address} emailAddressId={selectedAddressId} onChange={id => setSelectedAddressId(id)} /> - <Label> - Subject + <TooltipLabel label={EMAIL_INJECT_FORM.subject}> <InputGroup placeholder='Input text' value={subject} onChange={e => setSubject(e.target.value)} /> - </Label> - <Label> - Content + </TooltipLabel> + <TooltipLabel label={EMAIL_INJECT_FORM.content}> <TextArea value={content} style={{ @@ -88,17 +84,20 @@ const EmailInjectForm: FC<EmailInjectFormProps> = ({ injectInfoId }) => { placeholder='Input text' onChange={e => setContent(e.target.value)} /> - </Label> - <Label> - Extra copies + </TooltipLabel> + <TooltipLabel label={EMAIL_INJECT_FORM.extraCopies}> <NumericInput placeholder='Input number' min={0} value={extraCopies} onValueChange={(value: number) => setExtraCopies(value)} /> - </Label> - <FileSelector fileId={fileId} onChange={id => setFileId(id)} /> + </TooltipLabel> + <FileSelector + label={EMAIL_INJECT_FORM.file} + fileId={fileId} + onChange={id => setFileId(id)} + /> <Button onClick={() => handleUpdateButton({ diff --git a/frontend/src/editor/InjectSpecification/InformationInjectForm.tsx b/frontend/src/editor/InjectSpecification/InformationInjectForm.tsx index 3c0efd073381fc41c9fb48d9574ba83de6fc7056..6d15950960d01dd5c37ea89145f3e48798095c90 100644 --- a/frontend/src/editor/InjectSpecification/InformationInjectForm.tsx +++ b/frontend/src/editor/InjectSpecification/InformationInjectForm.tsx @@ -1,8 +1,10 @@ -import { Button, Label, TextArea } from '@blueprintjs/core' +import { Button, TextArea } from '@blueprintjs/core' import { useNotifyContext } from '@inject/shared/notification/contexts/NotifyContext' import { useLiveQuery } from 'dexie-react-hooks' import { memo, useCallback, useEffect, useState, type FC } from 'react' import FileSelector from '../FileSelector' +import TooltipLabel from '../Tooltips/TooltipLabel' +import { INFORMATION_INJECT_FORM } from '../assets/pageContent/injectSpecification' import { addInformationInject, getInformationInjectByInjectInfoId, @@ -57,8 +59,7 @@ const InformationInjectForm: FC<InformationInjectFormProps> = ({ return ( <div> - <Label> - Content + <TooltipLabel label={INFORMATION_INJECT_FORM.content}> <TextArea value={content} style={{ @@ -70,8 +71,12 @@ const InformationInjectForm: FC<InformationInjectFormProps> = ({ placeholder='Input text' onChange={e => setContent(e.target.value)} /> - </Label> - <FileSelector fileId={fileId} onChange={id => setFileId(id)} /> + </TooltipLabel> + <FileSelector + label={INFORMATION_INJECT_FORM.file} + fileId={fileId} + onChange={id => setFileId(id)} + /> <Button onClick={() => handleUpdateButton({ diff --git a/frontend/src/editor/InjectSpecification/OverlayForm.tsx b/frontend/src/editor/InjectSpecification/OverlayForm.tsx index bebc0dec925aec3b3ec7d876a73e85fff032088f..d3aafeee00492b919ae9759dde8bfcb901976559 100644 --- a/frontend/src/editor/InjectSpecification/OverlayForm.tsx +++ b/frontend/src/editor/InjectSpecification/OverlayForm.tsx @@ -1,7 +1,10 @@ -import { Button, Checkbox, Label, NumericInput } from '@blueprintjs/core' +import { Button, NumericInput } from '@blueprintjs/core' import { useNotifyContext } from '@inject/shared/notification/contexts/NotifyContext' import { useLiveQuery } from 'dexie-react-hooks' import { memo, useCallback, useEffect, useState, type FC } from 'react' +import TooltipCheckbox from '../Tooltips/TooltipCheckbox' +import TooltipLabel from '../Tooltips/TooltipLabel' +import { OVERLAY_FORM } from '../assets/pageContent/injectSpecification' import { addOverlay, deleteOverlay, @@ -60,21 +63,22 @@ const OverlayForm: FC<OverlayFormProps> = ({ injectInfoId }) => { return ( <div> - <Checkbox - checked={enableOverlay} - onChange={() => setEnableOverlay(prev => !prev)} - label={'Use overlay'} + <TooltipCheckbox + label={OVERLAY_FORM.enableOverlay} + checkboxProps={{ + checked: enableOverlay, + onChange: () => setEnableOverlay(!enableOverlay), + }} /> {enableOverlay && ( - <Label> - Duration in minutes + <TooltipLabel label={OVERLAY_FORM.duration}> <NumericInput placeholder='Input number' min={1} value={duration} onValueChange={(value: number) => setDuration(value)} /> - </Label> + </TooltipLabel> )} <Button onClick={() => diff --git a/frontend/src/editor/InjectSpecification/QuestionnaireForm/CustomLabelForm.tsx b/frontend/src/editor/InjectSpecification/QuestionnaireForm/CustomLabelForm.tsx index 55b78cb3dfa346871d33bf3890d68f11a96e5dc6..365760a1800a0e84b0d5d7839b0bd04258e81ef8 100644 --- a/frontend/src/editor/InjectSpecification/QuestionnaireForm/CustomLabelForm.tsx +++ b/frontend/src/editor/InjectSpecification/QuestionnaireForm/CustomLabelForm.tsx @@ -1,11 +1,6 @@ -import { - Button, - Colors, - Icon, - InputGroup, - Intent, - Label, -} from '@blueprintjs/core' +import TooltipLabel from '@/editor/Tooltips/TooltipLabel' +import { QUESTIONNAIRE_QUESTION_FORM } from '@/editor/assets/pageContent/injectSpecification' +import { Button, Colors, Icon, InputGroup, Intent } from '@blueprintjs/core' import type { FC } from 'react' import { memo, useCallback, useEffect, useState } from 'react' @@ -32,15 +27,17 @@ const CustomLabelForm: FC<CustomLabelFormProps> = ({ onAdd }) => { return ( <div> <div style={{ display: 'flex', alignItems: 'end' }}> - <Label style={{ flexGrow: '1', marginBottom: '0' }}> - New answer + <TooltipLabel + label={QUESTIONNAIRE_QUESTION_FORM.newAnswer} + style={{ flexGrow: '1', marginBottom: '0' }} + > <InputGroup placeholder='Input text' value={newAnswer} onChange={e => setNewAnswer(e.target.value)} intent={isValid ? Intent.NONE : Intent.DANGER} /> - </Label> + </TooltipLabel> <Button icon='plus' minimal diff --git a/frontend/src/editor/InjectSpecification/QuestionnaireForm/QuestionCustomLabels.tsx b/frontend/src/editor/InjectSpecification/QuestionnaireForm/QuestionCustomLabels.tsx index f3a9c94f38172a2a32f36f744602ea023b43a605..db891320ba8813c900000c1bcf129f2a9bb56c83 100644 --- a/frontend/src/editor/InjectSpecification/QuestionnaireForm/QuestionCustomLabels.tsx +++ b/frontend/src/editor/InjectSpecification/QuestionnaireForm/QuestionCustomLabels.tsx @@ -1,3 +1,5 @@ +import TooltipLabel from '@/editor/Tooltips/TooltipLabel' +import { QUESTIONNAIRE_QUESTION_FORM } from '@/editor/assets/pageContent/injectSpecification' import type { OptionProps } from '@blueprintjs/core' import { Button, @@ -68,8 +70,8 @@ const QuestionCustomLabels: FC<QuestionCustomLabelsProps> = ({ ) return ( - <> - <RadioGroup label={'Answers'} onChange={() => {}}> + <TooltipLabel label={QUESTIONNAIRE_QUESTION_FORM.answers}> + <RadioGroup onChange={() => {}}> {options.length > 0 ? ( options.map(option => ( <ControlGroup key={option.value} style={{ display: 'flex' }}> @@ -89,7 +91,7 @@ const QuestionCustomLabels: FC<QuestionCustomLabelsProps> = ({ style={{ display: 'flex', alignItems: 'center', - padding: '0 0 1rem', + padding: '1rem 0', }} > <Icon icon='disable' style={{ marginRight: '0.5rem' }} /> @@ -98,7 +100,7 @@ const QuestionCustomLabels: FC<QuestionCustomLabelsProps> = ({ )} </RadioGroup> <CustomLabelForm onAdd={(answer: string) => onAdd(answer)} /> - </> + </TooltipLabel> ) } diff --git a/frontend/src/editor/InjectSpecification/QuestionnaireForm/QuestionRangeLabels.tsx b/frontend/src/editor/InjectSpecification/QuestionnaireForm/QuestionRangeLabels.tsx index a713b212577975acfffefdc99c445b39b6f7f80b..efe981d5cad23b31d922dbe86c42822775101330 100644 --- a/frontend/src/editor/InjectSpecification/QuestionnaireForm/QuestionRangeLabels.tsx +++ b/frontend/src/editor/InjectSpecification/QuestionnaireForm/QuestionRangeLabels.tsx @@ -1,7 +1,8 @@ +import TooltipLabel from '@/editor/Tooltips/TooltipLabel' +import { QUESTIONNAIRE_QUESTION_FORM } from '@/editor/assets/pageContent/injectSpecification' import type { OptionProps } from '@blueprintjs/core' import { ControlGroup, - Label, NumericInput, Radio, RadioGroup, @@ -39,28 +40,29 @@ const QuestionRangeLabels: FC<QuestionRangeLabelsProps> = ({ return ( <div> - <Label> - Number of answers + <TooltipLabel label={QUESTIONNAIRE_QUESTION_FORM.max}> <NumericInput placeholder='Input number' min={1} value={max} onValueChange={(value: number) => onMaxChange(value)} /> - </Label> - <RadioGroup label={'Answers'} onChange={() => {}}> - {options.map(option => ( - <ControlGroup key={option.value}> - <Radio - label={option.label} - value={option.value} - checked={correct === option.value} - onClick={e => onCorrectChange(Number(e.currentTarget.value))} - onChange={() => {}} - /> - </ControlGroup> - ))} - </RadioGroup> + </TooltipLabel> + <TooltipLabel label={QUESTIONNAIRE_QUESTION_FORM.answers}> + <RadioGroup onChange={() => {}}> + {options.map(option => ( + <ControlGroup key={option.value}> + <Radio + label={option.label} + value={option.value} + checked={correct === option.value} + onClick={e => onCorrectChange(Number(e.currentTarget.value))} + onChange={() => {}} + /> + </ControlGroup> + ))} + </RadioGroup> + </TooltipLabel> </div> ) } diff --git a/frontend/src/editor/InjectSpecification/QuestionnaireForm/QuestionnaireQuestionForm.tsx b/frontend/src/editor/InjectSpecification/QuestionnaireForm/QuestionnaireQuestionForm.tsx index bb4c6380298d7c895bb511b6f2cfc213b880b94b..f8a6b1567b092667edc83f66fb2157eb2671eb30 100644 --- a/frontend/src/editor/InjectSpecification/QuestionnaireForm/QuestionnaireQuestionForm.tsx +++ b/frontend/src/editor/InjectSpecification/QuestionnaireForm/QuestionnaireQuestionForm.tsx @@ -1,3 +1,6 @@ +import TooltipLabel from '@/editor/Tooltips/TooltipLabel' +import TooltipSwitch from '@/editor/Tooltips/TooltipSwitch' +import { QUESTIONNAIRE_QUESTION_FORM } from '@/editor/assets/pageContent/injectSpecification' import { addQuestionnaireQuestion, updateQuestionnaireQuestion, @@ -9,8 +12,6 @@ import { DialogBody, DialogFooter, InputGroup, - Label, - Switch, } from '@blueprintjs/core' import { useNotifyContext } from '@inject/shared/notification/contexts/NotifyContext' import type { FC } from 'react' @@ -127,18 +128,19 @@ const QuestionnaireQuestionForm: FC<QuestionnaireQuestionFormProps> = ({ } > <DialogBody> - <Label> - Text + <TooltipLabel label={QUESTIONNAIRE_QUESTION_FORM.text}> <InputGroup placeholder='Input text' value={text} onChange={e => setText(e.target.value)} /> - </Label> - <Switch - label='Custom labels' - checked={customLabels} - onChange={() => setCustomLabels(prev => !prev)} + </TooltipLabel> + <TooltipSwitch + label={QUESTIONNAIRE_QUESTION_FORM.customLabels} + switchProps={{ + checked: customLabels, + onChange: () => setCustomLabels(!customLabels), + }} /> {customLabels ? ( <QuestionCustomLabels diff --git a/frontend/src/editor/InjectSpecification/QuestionnaireForm/QuestionnaireQuestions.tsx b/frontend/src/editor/InjectSpecification/QuestionnaireForm/QuestionnaireQuestions.tsx index 25a492f717443914ff3a567306c20d96aebf375c..b004119f37cce96d39a4588310eda39636576a51 100644 --- a/frontend/src/editor/InjectSpecification/QuestionnaireForm/QuestionnaireQuestions.tsx +++ b/frontend/src/editor/InjectSpecification/QuestionnaireForm/QuestionnaireQuestions.tsx @@ -1,3 +1,5 @@ +import TooltipLabel from '@/editor/Tooltips/TooltipLabel' +import { QUESTIONNAIRE_FORM } from '@/editor/assets/pageContent/injectSpecification' import { db } from '@/editor/indexeddb/db' import type { QuestionnaireQuestion } from '@/editor/indexeddb/types' import { CardList } from '@blueprintjs/core' @@ -20,9 +22,8 @@ const QuestionnaireQuestions: FC<QuestionnaireQuestionsProps> = ({ ) return ( - <> - <p>Questions</p> - <CardList> + <TooltipLabel label={QUESTIONNAIRE_FORM.questions}> + <CardList style={{ marginTop: '1rem' }}> {questionnaireQuestions?.map((question: QuestionnaireQuestion) => ( <QuestionnaireQuestionItem key={question.id} @@ -30,7 +31,7 @@ const QuestionnaireQuestions: FC<QuestionnaireQuestionsProps> = ({ /> ))} </CardList> - </> + </TooltipLabel> ) } diff --git a/frontend/src/editor/InjectSpecification/QuestionnaireForm/index.tsx b/frontend/src/editor/InjectSpecification/QuestionnaireForm/index.tsx index 2bd9d52382dcab85e8e3f4d3a47ef39229c5d268..cd25b3344af5eee87be5789a12a08a359fa28d65 100644 --- a/frontend/src/editor/InjectSpecification/QuestionnaireForm/index.tsx +++ b/frontend/src/editor/InjectSpecification/QuestionnaireForm/index.tsx @@ -1,4 +1,6 @@ -import { Button, InputGroup, Label } from '@blueprintjs/core' +import TooltipLabel from '@/editor/Tooltips/TooltipLabel' +import { QUESTIONNAIRE_FORM } from '@/editor/assets/pageContent/injectSpecification' +import { Button, InputGroup } from '@blueprintjs/core' import { useNotifyContext } from '@inject/shared/notification/contexts/NotifyContext' import { useLiveQuery } from 'dexie-react-hooks' import { memo, useCallback, useEffect, useState, type FC } from 'react' @@ -56,14 +58,13 @@ const QuestionnaireForm: FC<QuestionnaireFormProps> = ({ injectInfoId }) => { return ( <div> - <Label> - Title + <TooltipLabel label={QUESTIONNAIRE_FORM.title}> <InputGroup placeholder='Input text' value={title} onChange={e => setTitle(e.target.value)} /> - </Label> + </TooltipLabel> {questionnaire && ( <> <QuestionnaireQuestions questionnaireId={questionnaire.id} /> diff --git a/frontend/src/editor/IntroductionForm/index.tsx b/frontend/src/editor/IntroductionForm/index.tsx index 957f51d21a6c2b00cec91307c5b068ea5c89c631..64c6f4fa73dac9f608c6facea830dbbb6cccea41 100644 --- a/frontend/src/editor/IntroductionForm/index.tsx +++ b/frontend/src/editor/IntroductionForm/index.tsx @@ -1,12 +1,12 @@ import Checklist from '@/editor/Checklist' import useEditorStorage from '@/editor/useEditorStorage' import { memo, useEffect, useState } from 'react' -import { INTRO_CONDITIONS } from '../utils' +import { INTRODUCTION_CONDITIONS } from '../assets/pageContent/introduction' const IntroductionForm = () => { const [config, setConfig] = useEditorStorage() const [conditionChecked, setConditionChecked] = useState( - config?.introChecked || INTRO_CONDITIONS.map(() => false) + config?.introChecked || INTRODUCTION_CONDITIONS.map(() => false) ) useEffect(() => { @@ -18,7 +18,7 @@ const IntroductionForm = () => { return ( <Checklist - conditions={INTRO_CONDITIONS} + conditions={INTRODUCTION_CONDITIONS} initChecked={conditionChecked} onInputChange={(conditionChecked: boolean[]) => setConditionChecked(conditionChecked) diff --git a/frontend/src/editor/LandingPage/index.tsx b/frontend/src/editor/LandingPage/index.tsx index 8be7124d071b5c699f3a483c0f87048a351ffe93..00ddcc1106bcc57cec929afa68dea2f4dc6a97c1 100644 --- a/frontend/src/editor/LandingPage/index.tsx +++ b/frontend/src/editor/LandingPage/index.tsx @@ -6,7 +6,10 @@ import Container from '@inject/shared/components/Container' import { isEmpty } from 'lodash' import { useEffect, useState } from 'react' import DataRemovalDialog from '../DataRemovalDialog' +import { LANDING_PAGE_ACTIONS } from '../assets/pageContent/landingPage' +import { PAGE_INFORMATION } from '../assets/pageInformation' import { isDbEmpty } from '../indexeddb/operations' +import { PageNames } from '../types' import useEditorStorage from '../useEditorStorage' const introduction = css` @@ -43,21 +46,27 @@ const LandingPage = () => { }} /> <div className={introduction}> - <h1>Editor</h1> - <p>Placeholder.</p> + <h1>{PAGE_INFORMATION[PageNames.LANDING_PAGE].title}</h1> + <p + dangerouslySetInnerHTML={{ + __html: PAGE_INFORMATION[PageNames.LANDING_PAGE].description, + }} + /> <Button type='button' intent='primary' icon={isDataEmpty ? 'plus' : 'arrow-right'} onClick={() => nav('/editor/create/introduction')} > - {isDataEmpty ? 'Create' : 'Continue editing'} + {isDataEmpty + ? LANDING_PAGE_ACTIONS.create + : LANDING_PAGE_ACTIONS.edit} </Button> {!isDataEmpty && ( <DataRemovalDialog openButtonProps={{ icon: 'plus', - text: 'Create new', + text: LANDING_PAGE_ACTIONS.create, }} confirmButtonProps={{ intent: 'primary', diff --git a/frontend/src/editor/LearningActivityForm/index.tsx b/frontend/src/editor/LearningActivityForm/index.tsx index ab0f9f402bd3d950fe01fb8e96ec58d1127ee724..4172918db9d00f059747d73b36bec4ea82e8c2f3 100644 --- a/frontend/src/editor/LearningActivityForm/index.tsx +++ b/frontend/src/editor/LearningActivityForm/index.tsx @@ -10,12 +10,13 @@ import { DialogFooter, HTMLSelect, InputGroup, - Label, TextArea, } from '@blueprintjs/core' import { useNotifyContext } from '@inject/shared/notification/contexts/NotifyContext' import type { FC } from 'react' import { memo, useCallback, useEffect, useState } from 'react' +import TooltipLabel from '../Tooltips/TooltipLabel' +import { LEARNING_ACTIVITY_FORM } from '../assets/pageContent/learningObjectives' import type { LearningActivityInfo } from '../indexeddb/types' import { LearningActivityType } from '../indexeddb/types' import { LEARNING_ACTIVITY_TYPES } from '../utils' @@ -95,16 +96,14 @@ const LearningActivityForm: FC<LearningActivityFormProps> = ({ } > <DialogBody> - <Label> - Title + <TooltipLabel label={LEARNING_ACTIVITY_FORM.name}> <InputGroup placeholder='Input text' value={name} onChange={e => setName(e.target.value)} /> - </Label> - <Label> - What is this activity about? (optional) + </TooltipLabel> + <TooltipLabel label={LEARNING_ACTIVITY_FORM.description}> <TextArea value={description} style={{ @@ -116,9 +115,8 @@ const LearningActivityForm: FC<LearningActivityFormProps> = ({ placeholder='Input text' onChange={e => setDescription(e.target.value)} /> - </Label> - <Label> - Channel + </TooltipLabel> + <TooltipLabel label={LEARNING_ACTIVITY_FORM.channel}> <HTMLSelect options={LEARNING_ACTIVITY_TYPES} value={type} @@ -126,7 +124,7 @@ const LearningActivityForm: FC<LearningActivityFormProps> = ({ setType(event.currentTarget.value as LearningActivityType) } /> - </Label> + </TooltipLabel> </DialogBody> <DialogFooter actions={ diff --git a/frontend/src/editor/LearningObjectiveForm/index.tsx b/frontend/src/editor/LearningObjectiveForm/index.tsx index a69c9f8af0558de000d7b25cb80c87b2f251a59b..fda5158064b0d27f1bd1ea9b5e0432dd2ba90764 100644 --- a/frontend/src/editor/LearningObjectiveForm/index.tsx +++ b/frontend/src/editor/LearningObjectiveForm/index.tsx @@ -9,11 +9,12 @@ import { DialogBody, DialogFooter, InputGroup, - Label, } from '@blueprintjs/core' import { useNotifyContext } from '@inject/shared/notification/contexts/NotifyContext' import type { FC } from 'react' import { memo, useCallback, useEffect, useState } from 'react' +import TooltipLabel from '../Tooltips/TooltipLabel' +import { LEARNING_OBJECTIVE_FORM } from '../assets/pageContent/learningObjectives' import type { LearningObjectiveInfo } from '../indexeddb/types' interface LearningObjectiveFormProps { @@ -83,14 +84,13 @@ const LearningObjectiveForm: FC<LearningObjectiveFormProps> = ({ } > <DialogBody> - <Label> - Title + <TooltipLabel label={LEARNING_OBJECTIVE_FORM.name}> <InputGroup placeholder='Input text' value={name} onChange={e => setName(e.target.value)} /> - </Label> + </TooltipLabel> </DialogBody> <DialogFooter actions={ diff --git a/frontend/src/editor/Navbar/NavbarButton.tsx b/frontend/src/editor/Navbar/NavbarButton.tsx index 15a154ce606dc457fe0c699843b9e531e731291a..e2ba6d0d977b6f1c7870bea92cbeca3365e56bb7 100644 --- a/frontend/src/editor/Navbar/NavbarButton.tsx +++ b/frontend/src/editor/Navbar/NavbarButton.tsx @@ -2,15 +2,18 @@ import type { Path } from '@/router' import { useNavigate } from '@/router' import { Button } from '@blueprintjs/core' import type { FC } from 'react' +import { NAVIGATION_CONTENT } from '../assets/navigationContent' +import type { NavigationLinkNames } from '../types' interface NavbarButtonProps { path: Path - name: string + linkKey: NavigationLinkNames visible?: boolean } -const NavbarButton: FC<NavbarButtonProps> = ({ path, name, visible }) => { +const NavbarButton: FC<NavbarButtonProps> = ({ path, linkKey, visible }) => { const nav = useNavigate() + const name = NAVIGATION_CONTENT.links[linkKey] if (!visible) return diff --git a/frontend/src/editor/Navbar/index.tsx b/frontend/src/editor/Navbar/index.tsx index 86dc2e9a7d3b050560d36f7d91c189b407550ba6..69fcf2483efccaf1e0a6aef2b400df5b3b2f77de 100644 --- a/frontend/src/editor/Navbar/index.tsx +++ b/frontend/src/editor/Navbar/index.tsx @@ -1,4 +1,5 @@ import { memo } from 'react' +import { NavigationLinkNames } from '../types' import useEditorAccessStorage from '../useEditorAccessStorage' import NavbarButton from './NavbarButton' @@ -9,52 +10,52 @@ const Navbar = () => { <div style={{ display: 'flex', flexDirection: 'column' }}> <NavbarButton path='/editor/create/introduction' - name='Introduction' + linkKey={NavigationLinkNames.INTRODUCTION} visible /> <NavbarButton path='/editor/create/exercise-information' - name='Exercise information' + linkKey={NavigationLinkNames.EXERCISE_INFORMATION} visible={access?.introductionFilled} /> <NavbarButton path='/editor/create/learning-objectives' - name='Learning objectives' + linkKey={NavigationLinkNames.LEARNING_OBJECTIVES} visible={access?.exerciseInformationFilled} /> <NavbarButton path='/editor/create/injects' - name='Injects' + linkKey={NavigationLinkNames.INJECTS} visible={access?.objectivesFilled} /> <NavbarButton path='/editor/create/activity-specification' - name='Activities specification' + linkKey={NavigationLinkNames.ACTIVITY_SPECIFICATION_OVERVIEW} visible={access?.injectsFilled} /> <NavbarButton path='/editor/create/inject-specification' - name='Injects specification' + linkKey={NavigationLinkNames.INJECT_SPECIFICATION_OVERVIEW} visible={access?.injectsFilled} /> <NavbarButton path='/editor/create/other' - name='Other' + linkKey={NavigationLinkNames.OTHER} visible={access?.injectsFilled} /> <NavbarButton path='/editor/create/final-information' - name='Final Information' + linkKey={NavigationLinkNames.FINAL_INFORMATION} visible={access?.specificationsFilled} /> <NavbarButton path='/editor/create/conclusion' - name='Conclusion' + linkKey={NavigationLinkNames.CONCLUSION} visible={access?.finalInformationFilled} /> <NavbarButton path='/editor/create/download' - name='Download' + linkKey={NavigationLinkNames.DOWNLOAD} visible={access?.conclusionFilled} /> </div> diff --git a/frontend/src/editor/ToolForm/index.tsx b/frontend/src/editor/ToolForm/index.tsx index 56899e07d97b08f25f2471e3056a1804e0827194..5212768b913c15e15d51d1843c249c3b7c8b767f 100644 --- a/frontend/src/editor/ToolForm/index.tsx +++ b/frontend/src/editor/ToolForm/index.tsx @@ -6,12 +6,13 @@ import { DialogBody, DialogFooter, InputGroup, - Label, TextArea, } from '@blueprintjs/core' import { useNotifyContext } from '@inject/shared/notification/contexts/NotifyContext' import type { FC } from 'react' import { memo, useCallback, useEffect, useState } from 'react' +import TooltipLabel from '../Tooltips/TooltipLabel' +import { TOOL_FORM } from '../assets/pageContent/tools' import type { ToolInfo } from '../indexeddb/types' interface ToolFormProps { @@ -86,40 +87,35 @@ const ToolForm: FC<ToolFormProps> = ({ toolInfo, buttonProps, onAdd }) => { title={toolInfo ? 'Edit tool' : 'New tool'} > <DialogBody> - <Label> - Name + <TooltipLabel label={TOOL_FORM.name}> <InputGroup placeholder='Input text' value={name} onChange={e => setName(e.target.value)} /> - </Label> - <Label> - Category + </TooltipLabel> + <TooltipLabel label={TOOL_FORM.category}> <InputGroup placeholder='Input text' value={category} onChange={e => setCategory(e.target.value)} /> - </Label> - <Label> - Tooltip description + </TooltipLabel> + <TooltipLabel label={TOOL_FORM.tooltip}> <InputGroup placeholder='Input text' value={tooltipDescription} onChange={e => setTooltipDescription(e.target.value)} /> - </Label> - <Label> - Hint + </TooltipLabel> + <TooltipLabel label={TOOL_FORM.hint}> <InputGroup placeholder='Input text' value={hint} onChange={e => setHint(e.target.value)} /> - </Label> - <Label> - Default Response + </TooltipLabel> + <TooltipLabel label={TOOL_FORM.defaultResponse}> <TextArea value={defaultResponse} style={{ @@ -131,7 +127,7 @@ const ToolForm: FC<ToolFormProps> = ({ toolInfo, buttonProps, onAdd }) => { placeholder='Input text' onChange={e => setDefaultResponse(e.target.value)} /> - </Label> + </TooltipLabel> </DialogBody> <DialogFooter actions={ diff --git a/frontend/src/editor/ToolResponseFormContent/index.tsx b/frontend/src/editor/ToolResponseFormContent/index.tsx index 074dd3a4d45b62b4fc7436052f6ce7c7ab0c31f8..6cbbfadc15c2dc229c821249d465d803a559a3de 100644 --- a/frontend/src/editor/ToolResponseFormContent/index.tsx +++ b/frontend/src/editor/ToolResponseFormContent/index.tsx @@ -1,7 +1,5 @@ import { - Checkbox, InputGroup, - Label, NumericInput, Tab, Tabs, @@ -12,6 +10,12 @@ import { memo, type FC } from 'react' import ExpressionBuilder from '../ExpressionBuilder' import FileSelector from '../FileSelector' import ToolSelector from '../ToolSelector' +import TooltipCheckbox from '../Tooltips/TooltipCheckbox' +import TooltipLabel from '../Tooltips/TooltipLabel' +import { + TOOL_RESPONSE_CONNECTIONS_FORM, + TOOL_RESPONSE_FORM, +} from '../assets/pageContent/tools' interface ToolResponseFormProps { parameter: string @@ -52,22 +56,26 @@ const ToolResponseForm: FC<ToolResponseFormProps> = ({ title='Parameters' panel={ <div> - <ToolSelector toolId={toolId} onChange={id => onToolIdChange(id)} /> - <Label> - Parameter + <ToolSelector + label={TOOL_RESPONSE_FORM.tool} + toolId={toolId} + onChange={id => onToolIdChange(id)} + /> + <TooltipLabel label={TOOL_RESPONSE_FORM.parameter}> <InputGroup placeholder='Input text' value={parameter} onChange={e => onParameterChange(e.target.value)} /> - </Label> - <Checkbox - label='Is parameter regex?' - checked={isRegex} - onChange={e => onIsRegexChange(e.target.checked)} + </TooltipLabel> + <TooltipCheckbox + label={TOOL_RESPONSE_FORM.isRegex} + checkboxProps={{ + checked: isRegex, + onChange: () => onIsRegexChange(!isRegex), + }} /> - <Label> - Response + <TooltipLabel label={TOOL_RESPONSE_FORM.response}> <TextArea value={content} style={{ @@ -79,8 +87,12 @@ const ToolResponseForm: FC<ToolResponseFormProps> = ({ placeholder='Input text' onChange={e => onContentChange(e.target.value)} /> - </Label> - <FileSelector fileId={fileId} onChange={id => onFileIdChange(id)} /> + </TooltipLabel> + <FileSelector + label={TOOL_RESPONSE_FORM.file} + fileId={fileId} + onChange={id => onFileIdChange(id)} + /> </div> } /> @@ -89,16 +101,16 @@ const ToolResponseForm: FC<ToolResponseFormProps> = ({ title='Connections' panel={ <div> - <Label> - Time + <TooltipLabel label={TOOL_RESPONSE_CONNECTIONS_FORM.time}> <NumericInput placeholder='Input number' min={0} value={time} onValueChange={(value: number) => onTimeChange(value)} /> - </Label> + </TooltipLabel> <ExpressionBuilder + label={TOOL_RESPONSE_CONNECTIONS_FORM.condition} initExpression={milestoneCondition} onExpressionChange={expression => onMilestoneConditionChange(expression) diff --git a/frontend/src/editor/ToolSelector/index.tsx b/frontend/src/editor/ToolSelector/index.tsx index e6a2d7bddb23d3564db15004b36a0a7abca60092..975e0fcf1313d0f92193f79a1e19d765200d32c4 100644 --- a/frontend/src/editor/ToolSelector/index.tsx +++ b/frontend/src/editor/ToolSelector/index.tsx @@ -1,17 +1,20 @@ import type { OptionProps } from '@blueprintjs/core' -import { HTMLSelect, Label } from '@blueprintjs/core' +import { HTMLSelect } from '@blueprintjs/core' import { useLiveQuery } from 'dexie-react-hooks' import { memo, useEffect, useMemo, type FC } from 'react' import ToolForm from '../ToolForm' +import TooltipLabel from '../Tooltips/TooltipLabel' import { db } from '../indexeddb/db' import type { ToolInfo } from '../indexeddb/types' +import type { ExtendedLabel } from '../types' interface ToolFormProps { + label: ExtendedLabel toolId: number onChange: (id: number) => void } -const ToolSelector: FC<ToolFormProps> = ({ toolId, onChange }) => { +const ToolSelector: FC<ToolFormProps> = ({ label, toolId, onChange }) => { const tools = useLiveQuery(() => db.tools.toArray(), [], []) const toolOptions: OptionProps[] = useMemo(() => { @@ -39,14 +42,13 @@ const ToolSelector: FC<ToolFormProps> = ({ toolId, onChange }) => { return ( <div style={{ display: 'flex', width: '100%' }}> - <Label style={{ flexGrow: '1' }}> - Tool + <TooltipLabel label={label} style={{ flexGrow: '1' }}> <HTMLSelect options={toolOptions} value={toolId} onChange={event => onChange(Number(event.currentTarget.value))} /> - </Label> + </TooltipLabel> <ToolForm buttonProps={{ minimal: true, diff --git a/frontend/src/editor/Tooltips/TooltipCheckbox/index.tsx b/frontend/src/editor/Tooltips/TooltipCheckbox/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..9c73c0f8ebc1923c7992deb150f6fbd6a45ec7bf --- /dev/null +++ b/frontend/src/editor/Tooltips/TooltipCheckbox/index.tsx @@ -0,0 +1,21 @@ +import type { CheckboxProps } from '@blueprintjs/core' +import { Checkbox } from '@blueprintjs/core' +import { memo, type FC } from 'react' +import type { ExtendedLabel } from '../../types' +import TooltipLabelContent from '../TooltipLabelContent' + +interface TooltipCheckboxProps { + label: ExtendedLabel + checkboxProps: CheckboxProps +} + +const TooltipCheckbox: FC<TooltipCheckboxProps> = ({ + label, + checkboxProps, +}) => ( + <Checkbox {...checkboxProps}> + <TooltipLabelContent label={label} /> + </Checkbox> +) + +export default memo(TooltipCheckbox) diff --git a/frontend/src/editor/Tooltips/TooltipLabel/index.tsx b/frontend/src/editor/Tooltips/TooltipLabel/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..35487f0ebbb12118e44d3f3a399e369c86ddb0ab --- /dev/null +++ b/frontend/src/editor/Tooltips/TooltipLabel/index.tsx @@ -0,0 +1,22 @@ +import { Label } from '@blueprintjs/core' +import type { CSSProperties, ReactNode } from 'react' +import { memo, type FC } from 'react' +import type { ExtendedLabel } from '../../types' +import TooltipLabelContent from '../TooltipLabelContent' + +interface TooltipLabelProps { + label: ExtendedLabel + children: ReactNode + style?: CSSProperties +} + +const TooltipLabel: FC<TooltipLabelProps> = ({ label, children, style }) => ( + <Label style={style}> + <div style={{ display: 'flex', alignItems: 'center' }}> + <TooltipLabelContent label={label} style={{ marginBottom: '0.3rem' }} /> + </div> + {children} + </Label> +) + +export default memo(TooltipLabel) diff --git a/frontend/src/editor/Tooltips/TooltipLabelContent/index.tsx b/frontend/src/editor/Tooltips/TooltipLabelContent/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..8ad9822c902f2c51192df00d3d26c8151f5486d6 --- /dev/null +++ b/frontend/src/editor/Tooltips/TooltipLabelContent/index.tsx @@ -0,0 +1,36 @@ +import { Classes, Icon, Tooltip } from '@blueprintjs/core' +import { css } from '@emotion/css' +import type { CSSProperties } from 'react' +import { memo, type FC } from 'react' +import type { ExtendedLabel } from '../../types' + +const helpIcon = css` + margin-left: 0.5rem; + cursor: pointer; +` + +interface TooltipLabelContentProps { + label: ExtendedLabel + style?: CSSProperties +} + +const TooltipLabelContent: FC<TooltipLabelContentProps> = ({ + label, + style, +}) => ( + <> + <span>{label.label}</span> + {!label.optional && <span style={{ marginLeft: '0.1rem' }}>*</span>} + {label.tooltip && ( + <Tooltip content={label.tooltip}> + <Icon + icon='help' + className={`${Classes.TEXT_MUTED} ${helpIcon}`} + style={{ ...style }} + /> + </Tooltip> + )} + </> +) + +export default memo(TooltipLabelContent) diff --git a/frontend/src/editor/Tooltips/TooltipSwitch/index.tsx b/frontend/src/editor/Tooltips/TooltipSwitch/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..bd875237f40d9ec80a65cfa605e6afad516bc524 --- /dev/null +++ b/frontend/src/editor/Tooltips/TooltipSwitch/index.tsx @@ -0,0 +1,19 @@ +import type { SwitchProps } from '@blueprintjs/core' +import { Switch } from '@blueprintjs/core' +import { memo, type FC } from 'react' +import type { ExtendedLabel } from '../../types' +import TooltipLabelContent from '../TooltipLabelContent' + +interface TooltipSwitchProps { + label: ExtendedLabel + switchProps?: SwitchProps +} + +const TooltipSwitch: FC<TooltipSwitchProps> = ({ label, switchProps }) => ( + <Switch + {...switchProps} + labelElement={<TooltipLabelContent label={label} />} + /> +) + +export default memo(TooltipSwitch) diff --git a/frontend/src/editor/assets/README.md b/frontend/src/editor/assets/README.md new file mode 100644 index 0000000000000000000000000000000000000000..69def44692c9c3b96470773bb8f1a1d9dd3affd1 --- /dev/null +++ b/frontend/src/editor/assets/README.md @@ -0,0 +1,83 @@ +## Directory structure + +### pageInformation.tsx +This file contains basic information about each page in form of a JavaScript object.\ +Each page is represented by a nested object. The whole object follows this structure: +``` +{ + pageName: { + title: 'Title', + description: 'Description' + faq: [ + { + question: 'Question?', + answer: 'Answer' + }, + ] + }, + ... +} +``` +- pageName - must not be changed +- title - required, plain string +- description - required, plain sting or use HTML for formatting +- faq - optional, contains a list (array) of question objects; new questions can be added by duplicating the question object structure + +Question object: +``` +{ + question: 'Question?', + answer: 'Answer' +}, +``` +- question - required, plain string +- required - require, plain string or HTML + +### navigationContent.tsx +The file contains navigation content that follows this structure: +``` +{ + title: 'Steps', + links: { + pageName1: 'Page 1', + pageName2: 'Page 2', + ... + }, +} +``` +- pageName - must not be changed +- title - required, plain string +- links object with page names and corresponding names displayed in navigation +- the names have to be specified and should not be empty + +### pageContent +Directory that contains multiple pages corresponding to pages in the app.\ +Each file in this directory contains checklist or form object(s) with following structure: + +**Checklist** +``` +[ + { name: 'Check 1', description: 'Description 1' }, + { name: 'Check 2', description: 'Description 2' }, + ... +] +``` +- name - required, plain string +- description - required, plain string +- the array can be extended by duplicating the check object + +**Form** +``` +{ + inputName: { + label: 'Final milestone', + tooltip: '', + optional: true + }, + ... +} +``` +- inputLabel - must not be changed +- label - required, plain string +- tooltip - optional, plain string +- optional - should not be changed, used as an indicator of whether the input field should be filled out diff --git a/frontend/src/editor/assets/generalContent.tsx b/frontend/src/editor/assets/generalContent.tsx new file mode 100644 index 0000000000000000000000000000000000000000..a7c91a2666c010ac3d55b066a1632967052f9179 --- /dev/null +++ b/frontend/src/editor/assets/generalContent.tsx @@ -0,0 +1,11 @@ +export const GENERIC_CONTENT = { + buttons: { + add: 'Add', + edit: 'Edit', + save: 'Save', + back: 'Back', + next: 'Next', + cancel: 'Cancel', + confirm: 'Confirm', + }, +} diff --git a/frontend/src/editor/assets/navigationContent.tsx b/frontend/src/editor/assets/navigationContent.tsx new file mode 100644 index 0000000000000000000000000000000000000000..3f63bc18b558529bb33056fc6f06cdc52abe98c0 --- /dev/null +++ b/frontend/src/editor/assets/navigationContent.tsx @@ -0,0 +1,17 @@ +import type { NavigationPage } from '../types' + +export const NAVIGATION_CONTENT: NavigationPage = { + title: 'Steps', + links: { + introduction: 'Introduction', + exerciseInformation: 'Exercise information', + learningObjectives: 'Learning objectives', + injects: 'Injects', + activitySpecificationOverview: 'Activities specification', + injectSpecificationOverview: 'Injects specification', + other: 'Other', + finalInformation: 'Final information', + conclusion: 'Conclusion', + download: 'Download', + }, +} diff --git a/frontend/src/editor/assets/pageContent/conclusion.tsx b/frontend/src/editor/assets/pageContent/conclusion.tsx new file mode 100644 index 0000000000000000000000000000000000000000..a212173f29ff88435dbb61e193ba3a6e4f8ad38d --- /dev/null +++ b/frontend/src/editor/assets/pageContent/conclusion.tsx @@ -0,0 +1,7 @@ +import type { Checklist } from '@/editor/types' + +export const CONCLUSION_CONDITIONS: Checklist = [ + { name: 'Check 1', description: 'Description' }, + { name: 'Check 2', description: 'Description' }, + { name: 'Check 3', description: 'Description' }, +] diff --git a/frontend/src/editor/assets/pageContent/emails.tsx b/frontend/src/editor/assets/pageContent/emails.tsx new file mode 100644 index 0000000000000000000000000000000000000000..428581762b22467f54e04933a7d2875b7937e6cb --- /dev/null +++ b/frontend/src/editor/assets/pageContent/emails.tsx @@ -0,0 +1,43 @@ +import type { Form } from '@/editor/types' + +export const EMAIL_ADDRESS_FORM: Form = { + address: { + label: 'Address', + tooltip: '', + }, + organization: { + label: 'Organization', + tooltip: '', + optional: true, + }, + description: { + label: 'Description', + tooltip: '', + }, + teamVisible: { + label: 'Team visible', + tooltip: '', + optional: true, + }, +} + +export const EMAIL_TEMPLATE_FORM: Form = { + address: { + label: 'Address', + tooltip: '', + }, + context: { + label: 'Context', + tooltip: '', + }, + content: { + label: 'Content', + tooltip: '', + optional: true, + }, + file: { + label: 'File', + tooltip: '', + optional: true, + }, +} diff --git a/frontend/src/editor/assets/pageContent/exerciseInformation.tsx b/frontend/src/editor/assets/pageContent/exerciseInformation.tsx new file mode 100644 index 0000000000000000000000000000000000000000..a90eaa35523f776b0bd69d6e9ae11bd909b04bed --- /dev/null +++ b/frontend/src/editor/assets/pageContent/exerciseInformation.tsx @@ -0,0 +1,16 @@ +import type { Form } from '@/editor/types' + +export const EXERCISE_INFORMATION_FORM: Form = { + name: { + label: 'Name', + tooltip: '', + }, + description: { + label: 'Description', + tooltip: '', + }, + trainee: { + label: 'Who is your trainee?', + tooltip: 'This is tooltip.', + }, +} diff --git a/frontend/src/editor/assets/pageContent/files.tsx b/frontend/src/editor/assets/pageContent/files.tsx new file mode 100644 index 0000000000000000000000000000000000000000..2fa470aec757323ec9bf35e184204bb799031c0f --- /dev/null +++ b/frontend/src/editor/assets/pageContent/files.tsx @@ -0,0 +1,14 @@ +import type { Form } from '@/editor/types' + +export const FILE_UPLOAD_FORM: Form = { + name: { + label: 'Name', + tooltip: '', + optional: true, + }, + file: { + label: 'File', + tooltip: '', + optional: true, + }, +} diff --git a/frontend/src/editor/assets/pageContent/finalInformation.tsx b/frontend/src/editor/assets/pageContent/finalInformation.tsx new file mode 100644 index 0000000000000000000000000000000000000000..e44e40fe47a50d2a5af882ccd89e42435cc27bcd --- /dev/null +++ b/frontend/src/editor/assets/pageContent/finalInformation.tsx @@ -0,0 +1,62 @@ +import type { Form } from '@/editor/types' + +export const EXERCISE_DURATION_FORM: Form = { + exerciseDuration: { + label: 'Exercise duration in minutes', + tooltip: '', + }, + showTime: { + label: 'Show exercise time to trainees', + tooltip: '', + optional: true, + }, +} + +export const FINAL_MILESTONE_FORM: Form = { + finalMilestone: { + label: 'Final milestone', + tooltip: '', + }, +} + +export const INFORMATION_CHANNEL_FORM: Form = { + name: { + label: 'Custom information channel name', + tooltip: '', + optional: true, + }, +} + +export const TOOL_CHANNEL_FORM: Form = { + name: { + label: 'Custom tool channel name', + tooltip: '', + optional: true, + }, +} + +export const EMAIL_CHANNEL_FORM: Form = { + name: { + label: 'Custom email channel name', + tooltip: '', + optional: true, + }, + emailsBetweenTeams: { + label: 'Enable emails between teams', + tooltip: '', + optional: true, + }, + suffix: { + label: 'Custom email suffix', + tooltip: '', + optional: true, + }, +} + +export const QUESTIONNAIRE_CHANNEL_FORM: Form = { + name: { + label: 'Custom form channel name', + tooltip: '', + optional: true, + }, +} diff --git a/frontend/src/editor/assets/pageContent/injectSpecification.tsx b/frontend/src/editor/assets/pageContent/injectSpecification.tsx new file mode 100644 index 0000000000000000000000000000000000000000..9463f6be07e8ecb93a405e6fe43a278091de6295 --- /dev/null +++ b/frontend/src/editor/assets/pageContent/injectSpecification.tsx @@ -0,0 +1,107 @@ +import type { Form } from '@/editor/types' + +export const INJECT_CONNECTIONS_FORM: Form = { + time: { + label: 'Start', + tooltip: '', + optional: true, + }, + delay: { + label: 'Start', + tooltip: '', + optional: true, + }, + condition: { + label: 'Condition', + tooltip: '', + optional: true, + }, +} + +export const OVERLAY_FORM: Form = { + enableOverlay: { + label: 'Use overlay', + tooltip: '', + optional: true, + }, + duration: { + label: 'Duration in minutes', + tooltip: '', + optional: true, + }, +} + +export const INFORMATION_INJECT_FORM: Form = { + content: { + label: 'Content', + tooltip: '', + optional: true, + }, + file: { + label: 'File', + tooltip: '', + optional: true, + }, +} + +export const EMAIL_INJECT_FORM: Form = { + address: { + label: 'Address', + tooltip: '', + }, + subject: { + label: 'Subject', + tooltip: '', + }, + content: { + label: 'Content', + tooltip: '', + optional: true, + }, + extraCopies: { + label: 'Extra copies', + tooltip: '', + optional: true, + }, + file: { + label: 'File', + tooltip: '', + optional: true, + }, +} + +export const QUESTIONNAIRE_FORM: Form = { + title: { + label: 'Title', + tooltip: '', + }, + questions: { + label: 'Questions', + tooltip: '', + }, +} + +export const QUESTIONNAIRE_QUESTION_FORM: Form = { + text: { + label: 'Text', + tooltip: '', + }, + customLabels: { + label: 'Custom labels', + tooltip: '', + optional: true, + }, + max: { + label: 'Number of answers', + tooltip: '', + }, + answers: { + label: 'Answers', + tooltip: '', + }, + newAnswer: { + label: 'New answer', + tooltip: '', + optional: true, + }, +} diff --git a/frontend/src/editor/assets/pageContent/injects.tsx b/frontend/src/editor/assets/pageContent/injects.tsx new file mode 100644 index 0000000000000000000000000000000000000000..2d579fa5206df56f032b91c9c81573e19180025b --- /dev/null +++ b/frontend/src/editor/assets/pageContent/injects.tsx @@ -0,0 +1,17 @@ +import type { Form } from '@/editor/types' + +export const INJECT_FORM: Form = { + name: { + label: 'Title', + tooltip: '', + }, + description: { + label: 'What is this inject about?', + tooltip: '', + optional: true, + }, + channel: { + label: 'Channel', + tooltip: '', + }, +} diff --git a/frontend/src/editor/assets/pageContent/introduction.tsx b/frontend/src/editor/assets/pageContent/introduction.tsx new file mode 100644 index 0000000000000000000000000000000000000000..b9f67d8542c5727b5335a445c11682dbc0a8d2c8 --- /dev/null +++ b/frontend/src/editor/assets/pageContent/introduction.tsx @@ -0,0 +1,7 @@ +import type { Checklist } from '@/editor/types' + +export const INTRODUCTION_CONDITIONS: Checklist = [ + { name: 'Purpose', description: 'What do you want to achieve' }, + { name: 'Learning objectives', description: 'Description' }, + { name: 'Injects', description: 'Description' }, +] diff --git a/frontend/src/editor/assets/pageContent/landingPage.tsx b/frontend/src/editor/assets/pageContent/landingPage.tsx new file mode 100644 index 0000000000000000000000000000000000000000..a04192ff0bde41a8b1dca1d2b662a6c768a13423 --- /dev/null +++ b/frontend/src/editor/assets/pageContent/landingPage.tsx @@ -0,0 +1,4 @@ +export const LANDING_PAGE_ACTIONS = { + create: 'Create', + edit: 'Continue editing', +} diff --git a/frontend/src/editor/assets/pageContent/learningObjectives.tsx b/frontend/src/editor/assets/pageContent/learningObjectives.tsx new file mode 100644 index 0000000000000000000000000000000000000000..d373f7e32063a7d8de0b35a7ce114ce64256ff48 --- /dev/null +++ b/frontend/src/editor/assets/pageContent/learningObjectives.tsx @@ -0,0 +1,24 @@ +import type { Form } from '@/editor/types' + +export const LEARNING_OBJECTIVE_FORM: Form = { + name: { + label: 'Title', + tooltip: '', + }, +} + +export const LEARNING_ACTIVITY_FORM: Form = { + name: { + label: 'Title', + tooltip: '', + }, + description: { + label: 'What is this activity about?', + tooltip: '', + optional: true, + }, + channel: { + label: 'Channel', + tooltip: '', + }, +} diff --git a/frontend/src/editor/assets/pageContent/tools.tsx b/frontend/src/editor/assets/pageContent/tools.tsx new file mode 100644 index 0000000000000000000000000000000000000000..2dd1e9774d075f30635f2e0b3ac6bc7fe6407cd4 --- /dev/null +++ b/frontend/src/editor/assets/pageContent/tools.tsx @@ -0,0 +1,66 @@ +import type { Form } from '@/editor/types' + +export const TOOL_FORM: Form = { + name: { + label: 'Name', + tooltip: '', + }, + category: { + label: 'Category', + tooltip: '', + optional: true, + }, + tooltip: { + label: 'Tooltip description', + tooltip: '', + optional: true, + }, + hint: { + label: 'Hint', + tooltip: '', + optional: true, + }, + defaultResponse: { + label: 'Default response', + tooltip: '', + }, +} + +export const TOOL_RESPONSE_FORM: Form = { + tool: { + label: 'Tool', + tooltip: '', + }, + parameter: { + label: 'Parameter', + tooltip: '', + }, + isRegex: { + label: 'Is parameter regex?', + tooltip: '', + optional: true, + }, + response: { + label: 'Response', + tooltip: '', + optional: true, + }, + file: { + label: 'File', + tooltip: '', + optional: true, + }, +} + +export const TOOL_RESPONSE_CONNECTIONS_FORM: Form = { + time: { + label: 'Time', + tooltip: '', + optional: true, + }, + condition: { + label: 'Condition', + tooltip: '', + optional: true, + }, +} diff --git a/frontend/src/editor/assets/pageInformation.tsx b/frontend/src/editor/assets/pageInformation.tsx new file mode 100644 index 0000000000000000000000000000000000000000..51d3c3444a8a4784cea4ccf57b734091809d9e38 --- /dev/null +++ b/frontend/src/editor/assets/pageInformation.tsx @@ -0,0 +1,75 @@ +import type { PageInformation } from '../types' + +export const PAGE_INFORMATION: PageInformation = { + landingPage: { + title: 'Editor', + description: 'Placeholder', + }, + introduction: { + title: 'Before you start', + description: '<b>make sure</b> that you:', + }, + exerciseInformation: { + title: 'Exercise essentials', + description: 'Description.', + faq: [ + { + question: 'Question?', + answer: 'This is the <b>answer</b>.', + }, + { + question: 'What if...?', + answer: + 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit. <br/> Nulla accumsan, elit sit amet varius semper, nulla mauris mollis quam, tempor suscipit diam nulla vel leo.', + }, + ], + }, + learningObjectives: { + title: 'Define objectives and activities', + description: 'Description.', + }, + injects: { + title: 'Define injects', + description: 'Description.', + }, + activitySpecificationOverview: { + title: 'Define activities', + description: 'Description.', + }, + activitySpecification: { + title: 'Define activity', + description: 'Description.', + }, + injectSpecificationOverview: { + title: 'Define injects', + description: 'Description.', + }, + injectSpecification: { + title: 'Define inject', + description: 'Description.', + }, + other: { + title: 'Define other information', + description: 'Add new tools and email addresses to your exercise.', + }, + tools: { + title: 'Define tools', + description: 'Description.', + }, + emails: { + title: 'Define email addresses', + description: 'Description.', + }, + finalInformation: { + title: 'Final information', + description: 'Description.', + }, + conclusion: { + title: 'Before you finish', + description: 'make sure that you:', + }, + download: { + title: 'Download definition', + description: 'Description.', + }, +} diff --git a/frontend/src/editor/types.tsx b/frontend/src/editor/types.tsx new file mode 100644 index 0000000000000000000000000000000000000000..79a96ab4cd04055a4d3519d485575ae9c68b93ea --- /dev/null +++ b/frontend/src/editor/types.tsx @@ -0,0 +1,70 @@ +export enum PageNames { + LANDING_PAGE = 'landingPage', + INTRODUCTION = 'introduction', + EXERCISE_INFORMATION = 'exerciseInformation', + LEARNING_OBJECTIVES = 'learningObjectives', + INJECTS = 'injects', + ACTIVITY_SPECIFICATION_OVERVIEW = 'activitySpecificationOverview', + ACTIVITY_SPECIFICATION = 'activitySpecification', + INJECT_SPECIFICATION_OVERVIEW = 'injectSpecificationOverview', + INJECT_SPECIFICATION = 'injectSpecification', + OTHER = 'other', + TOOLS = 'tools', + EMAILS = 'emails', + FINAL_INFORMATION = 'finalInformation', + CONCLUSION = 'conclusion', + DOWNLOAD = 'download', +} + +export type FAQQuestion = { + question: string + answer: string +} + +export type PageContent = { + title: string + description: string +} + +type PageContentWithFaq = PageContent & { + faq?: FAQQuestion[] +} + +export type PageInformation = { + [key in PageNames]: PageContentWithFaq +} + +export enum NavigationLinkNames { + INTRODUCTION = 'introduction', + EXERCISE_INFORMATION = 'exerciseInformation', + LEARNING_OBJECTIVES = 'learningObjectives', + INJECTS = 'injects', + ACTIVITY_SPECIFICATION_OVERVIEW = 'activitySpecificationOverview', + INJECT_SPECIFICATION_OVERVIEW = 'injectSpecificationOverview', + OTHER = 'other', + FINAL_INFORMATION = 'finalInformation', + CONCLUSION = 'conclusion', + DOWNLOAD = 'download', +} + +export type NavigationPage = { + title: string + links: { [key in NavigationLinkNames]: string } +} + +type ChecklistItem = { + name: string + description?: string +} + +export type Checklist = ChecklistItem[] + +export type ExtendedLabel = { + label: string + optional?: boolean + tooltip?: string +} + +export type Form = { + [key: string]: ExtendedLabel +} diff --git a/frontend/src/editor/utils.tsx b/frontend/src/editor/utils.tsx index 47d004f13881d42aec4de3304fa979ef6cb3f1b7..95e18f77a3dcfe51f045ff5679aca386b4eda64c 100644 --- a/frontend/src/editor/utils.tsx +++ b/frontend/src/editor/utils.tsx @@ -1,4 +1,4 @@ -import type { OptionProps } from '@blueprintjs/core' +import type { IconName, OptionProps } from '@blueprintjs/core' import notEmpty from '@inject/shared/utils/notEmpty' import { isEqual } from 'lodash' import type { @@ -12,23 +12,13 @@ import { MilestoneEventType, } from './indexeddb/types' -export const INTRO_CONDITIONS = [ - { name: 'Purpose', description: 'What do you want to achieve' }, - { name: 'Learning objectives', description: 'Description' }, - { name: 'Injects', description: 'Description' }, -] - -export const CONCLUSION_CONDITIONS = [ - { name: 'Check 1', description: 'Description' }, - { name: 'Check 2', description: 'Description' }, - { name: 'Check 3', description: 'Description' }, -] - export const LEARNING_ACTIVITY_TYPES = Object.values(LearningActivityType) export const INJECT_TYPES = Object.values(InjectType) -export const getLearningActivityIcon = (activity: LearningActivityInfo) => { +export const getLearningActivityIcon = ( + activity: LearningActivityInfo +): IconName => { switch (activity.type) { case LearningActivityType.EMAIL: return 'envelope' @@ -39,7 +29,7 @@ export const getLearningActivityIcon = (activity: LearningActivityInfo) => { } } -export const getInjectIcon = (inject: InjectInfo) => { +export const getInjectIcon = (inject: InjectInfo): IconName => { switch (inject.type) { case InjectType.EMAIL: return 'envelope' diff --git a/frontend/src/pages/editor/create/activity-specification/[activityId]/index.tsx b/frontend/src/pages/editor/create/activity-specification/[activityId]/index.tsx index cee95ab13c65d6200d5b36b78140fa7c327efa1a..040e8fdb5ba7285573ade0259989ea505a13d1f9 100644 --- a/frontend/src/pages/editor/create/activity-specification/[activityId]/index.tsx +++ b/frontend/src/pages/editor/create/activity-specification/[activityId]/index.tsx @@ -1,5 +1,6 @@ import EditorPage from '@/editor/EditorPage' import LearningActivitySpecification from '@/editor/LearningActivitySpecification' +import { PageNames } from '@/editor/types' import useEditorAccessStorage from '@/editor/useEditorAccessStorage' import { useParams } from '@/router' import { memo } from 'react' @@ -12,8 +13,7 @@ const ActivitySpecificationPage = () => { return ( <EditorPage - title='Define activity' - description='Description.' + pageKey={PageNames.ACTIVITY_SPECIFICATION} prevPath='/editor/create/activity-specification' nextVisible={false} pageVisible={access?.injectsFilled} diff --git a/frontend/src/pages/editor/create/activity-specification/index.tsx b/frontend/src/pages/editor/create/activity-specification/index.tsx index 8e400b12b1bfc928d716cbc92b1bb79a246c7ffd..7e877e17b10b5c798d3217b064652a6b8339274c 100644 --- a/frontend/src/pages/editor/create/activity-specification/index.tsx +++ b/frontend/src/pages/editor/create/activity-specification/index.tsx @@ -1,5 +1,6 @@ import EditorPage from '@/editor/EditorPage' import LearningActivitiesOverview from '@/editor/LearningActivitiesOverview' +import { PageNames } from '@/editor/types' import useEditorAccessStorage from '@/editor/useEditorAccessStorage' import { memo } from 'react' @@ -8,8 +9,7 @@ const ActivitiesSpecificationPage = () => { return ( <EditorPage - title='Define activities' - description='Description.' + pageKey={PageNames.ACTIVITY_SPECIFICATION_OVERVIEW} prevPath='/editor/create/injects' nextPath='/editor/create/inject-specification' pageVisible={access?.injectsFilled} diff --git a/frontend/src/pages/editor/create/conclusion.tsx b/frontend/src/pages/editor/create/conclusion.tsx index dba54c542dc0d11fd555aaa777804d26fd237536..559cc513c103e3ee317acbb3b536f95aba78681c 100644 --- a/frontend/src/pages/editor/create/conclusion.tsx +++ b/frontend/src/pages/editor/create/conclusion.tsx @@ -1,5 +1,6 @@ import ConclusionForm from '@/editor/ConclusionForm' import EditorPage from '@/editor/EditorPage' +import { PageNames } from '@/editor/types' import useEditorAccessStorage from '@/editor/useEditorAccessStorage' import { memo } from 'react' @@ -8,8 +9,7 @@ const ConclusionPage = () => { return ( <EditorPage - title='Before you finish' - description='make sure that you:' + pageKey={PageNames.CONCLUSION} prevPath='/editor/create/final-information' nextPath='/editor/create/download' nextDisabled={!access?.conclusionFilled} diff --git a/frontend/src/pages/editor/create/download.tsx b/frontend/src/pages/editor/create/download.tsx index 0d2f91c89dccc72e99ddb5a58b5b06877763e4bb..7bb5feaf20d00eef7c29699f0715350591eae4ce 100644 --- a/frontend/src/pages/editor/create/download.tsx +++ b/frontend/src/pages/editor/create/download.tsx @@ -1,5 +1,6 @@ import DownloadDefinition from '@/editor/DownloadDefinition' import EditorPage from '@/editor/EditorPage' +import { PageNames } from '@/editor/types' import useEditorAccessStorage from '@/editor/useEditorAccessStorage' const DownloadPage = () => { @@ -7,8 +8,7 @@ const DownloadPage = () => { return ( <EditorPage - title='Download definition' - description='Description.' + pageKey={PageNames.DOWNLOAD} prevPath='/editor/create/conclusion' nextVisible={false} pageVisible={access?.conclusionFilled} diff --git a/frontend/src/pages/editor/create/emails.tsx b/frontend/src/pages/editor/create/emails.tsx index 7f1378d77e1f37b9d85556283f1f9b05fc58ca81..c3067f68065b9074f0a2a8742a4db7cb26c39973 100644 --- a/frontend/src/pages/editor/create/emails.tsx +++ b/frontend/src/pages/editor/create/emails.tsx @@ -1,6 +1,7 @@ import EditorPage from '@/editor/EditorPage' import EmailAddressForm from '@/editor/EmailAddressForm' import EmailAddresses from '@/editor/EmailAddresses' +import { PageNames } from '@/editor/types' import useEditorAccessStorage from '@/editor/useEditorAccessStorage' import { memo } from 'react' @@ -9,8 +10,7 @@ const EmailAddressesPage = () => { return ( <EditorPage - title='Define email addresses' - description='Description.' + pageKey={PageNames.EMAILS} prevPath='/editor/create/other' nextVisible={false} pageVisible={access?.injectsFilled} diff --git a/frontend/src/pages/editor/create/exercise-information.tsx b/frontend/src/pages/editor/create/exercise-information.tsx index 71cee23e0d9d94002fa672a78f9291b345b77ada..1996eb08a51049c1ac18d3e0c34d326c4a5d3882 100644 --- a/frontend/src/pages/editor/create/exercise-information.tsx +++ b/frontend/src/pages/editor/create/exercise-information.tsx @@ -1,5 +1,6 @@ import EditorPage from '@/editor/EditorPage' import ExerciseInformationForm from '@/editor/ExerciseInformationForm' +import { PageNames } from '@/editor/types' import useEditorAccessStorage from '@/editor/useEditorAccessStorage' import { memo } from 'react' @@ -8,8 +9,7 @@ const ExerciseInformationPage = () => { return ( <EditorPage - title='Exercise essentials' - description='Description.' + pageKey={PageNames.EXERCISE_INFORMATION} prevPath='/editor/create/introduction' nextPath='/editor/create/learning-objectives' pageVisible={access?.introductionFilled} diff --git a/frontend/src/pages/editor/create/final-information.tsx b/frontend/src/pages/editor/create/final-information.tsx index 3d561173d25ff26229533aa24000b5dfcb1bfed0..7d6768ffc3f497357be6665a792aa0eb465005b7 100644 --- a/frontend/src/pages/editor/create/final-information.tsx +++ b/frontend/src/pages/editor/create/final-information.tsx @@ -1,5 +1,6 @@ import EditorPage from '@/editor/EditorPage' import FinalInformationForm from '@/editor/FinalInformationForm' +import { PageNames } from '@/editor/types' import useEditorAccessStorage from '@/editor/useEditorAccessStorage' import { memo } from 'react' @@ -8,8 +9,7 @@ const FinalInformationPage = () => { return ( <EditorPage - title='Final information' - description='Description.' + pageKey={PageNames.FINAL_INFORMATION} prevPath='/editor/create/other' nextPath='/editor/create/conclusion' nextDisabled={!access?.finalInformationFilled} diff --git a/frontend/src/pages/editor/create/inject-specification/[injectId]/index.tsx b/frontend/src/pages/editor/create/inject-specification/[injectId]/index.tsx index b2ad5a406eba5fd33bd202e67276c57612a993aa..af1822f34fc69530695d830515cd0d918c1c0c54 100644 --- a/frontend/src/pages/editor/create/inject-specification/[injectId]/index.tsx +++ b/frontend/src/pages/editor/create/inject-specification/[injectId]/index.tsx @@ -1,5 +1,6 @@ import EditorPage from '@/editor/EditorPage' import InjectSpecification from '@/editor/InjectSpecification' +import { PageNames } from '@/editor/types' import useEditorAccessStorage from '@/editor/useEditorAccessStorage' import { useParams } from '@/router' import { memo } from 'react' @@ -12,8 +13,7 @@ const InjectSpecificationPage = () => { return ( <EditorPage - title='Define inject' - description='Description.' + pageKey={PageNames.INJECT_SPECIFICATION} prevPath='/editor/create/inject-specification' nextVisible={false} pageVisible={access?.injectsFilled} diff --git a/frontend/src/pages/editor/create/inject-specification/index.tsx b/frontend/src/pages/editor/create/inject-specification/index.tsx index f9a255cbb098688c56be12eac4e1947919871acd..a390b1fa2e132d62f62e48e269e6590eadf0964c 100644 --- a/frontend/src/pages/editor/create/inject-specification/index.tsx +++ b/frontend/src/pages/editor/create/inject-specification/index.tsx @@ -1,5 +1,6 @@ import EditorPage from '@/editor/EditorPage' import InjectsOverview from '@/editor/InjectsOverview' +import { PageNames } from '@/editor/types' import useEditorAccessStorage from '@/editor/useEditorAccessStorage' import { memo } from 'react' @@ -8,8 +9,7 @@ const ActivitiesSpecificationPage = () => { return ( <EditorPage - title='Define injects' - description='Description.' + pageKey={PageNames.INJECT_SPECIFICATION_OVERVIEW} prevPath='/editor/create/activity-specification' nextPath='/editor/create/other' pageVisible={access?.injectsFilled} diff --git a/frontend/src/pages/editor/create/injects.tsx b/frontend/src/pages/editor/create/injects.tsx index 74a3d5a4bd511ff157852b5ddd0dc7c35c57c387..a428bd0d07b7c4bf3f42c793694785cdc667d60e 100644 --- a/frontend/src/pages/editor/create/injects.tsx +++ b/frontend/src/pages/editor/create/injects.tsx @@ -1,6 +1,7 @@ import EditorPage from '@/editor/EditorPage' import InjectForm from '@/editor/InjectForm' import Injects from '@/editor/Injects' +import { PageNames } from '@/editor/types' import useEditorAccessStorage from '@/editor/useEditorAccessStorage' import { memo } from 'react' @@ -9,8 +10,7 @@ const InjectsPage = () => { return ( <EditorPage - title='Define injects' - description='Description.' + pageKey={PageNames.INJECTS} prevPath='/editor/create/learning-objectives' nextPath='/editor/create/activity-specification' pageVisible={access?.objectivesFilled} diff --git a/frontend/src/pages/editor/create/introduction.tsx b/frontend/src/pages/editor/create/introduction.tsx index d1fb9d1e2eec4f3b799ad86686dcf264eaffaa27..0a56ca100895094c7b0361c774820c8594f62676 100644 --- a/frontend/src/pages/editor/create/introduction.tsx +++ b/frontend/src/pages/editor/create/introduction.tsx @@ -1,5 +1,6 @@ import EditorPage from '@/editor/EditorPage' import IntroductionForm from '@/editor/IntroductionForm' +import { PageNames } from '@/editor/types' import useEditorAccessStorage from '@/editor/useEditorAccessStorage' import { memo } from 'react' @@ -8,8 +9,7 @@ const IntroductionPage = () => { return ( <EditorPage - title='Before you start' - description='make sure that you:' + pageKey={PageNames.INTRODUCTION} prevPath='/editor' nextPath='/editor/create/exercise-information' pageVisible diff --git a/frontend/src/pages/editor/create/learning-objectives.tsx b/frontend/src/pages/editor/create/learning-objectives.tsx index b5e509c0f9a8966782ddffa57ec8e4ad08512c7a..39e8190ca357d97ca680840a8c32eda21c0ac6e2 100644 --- a/frontend/src/pages/editor/create/learning-objectives.tsx +++ b/frontend/src/pages/editor/create/learning-objectives.tsx @@ -1,6 +1,7 @@ import EditorPage from '@/editor/EditorPage' import LearningObjectiveForm from '@/editor/LearningObjectiveForm' import LearningObjectives from '@/editor/LearningObjectives' +import { PageNames } from '@/editor/types' import useEditorAccessStorage from '@/editor/useEditorAccessStorage' import { memo } from 'react' @@ -9,8 +10,7 @@ const LearningObjectivesPage = () => { return ( <EditorPage - title='Define objectives and activities' - description='Description.' + pageKey={PageNames.LEARNING_OBJECTIVES} prevPath='/editor/create/exercise-information' nextPath='/editor/create/injects' pageVisible={access?.exerciseInformationFilled} diff --git a/frontend/src/pages/editor/create/other.tsx b/frontend/src/pages/editor/create/other.tsx index 3aadbcd90f16b6cecdf3b0f04b3d116708458ed6..5efc3b510699ff27e7795e3725cb524bbb50ebcd 100644 --- a/frontend/src/pages/editor/create/other.tsx +++ b/frontend/src/pages/editor/create/other.tsx @@ -1,4 +1,5 @@ import EditorPage from '@/editor/EditorPage' +import { PageNames } from '@/editor/types' import useEditorAccessStorage from '@/editor/useEditorAccessStorage' import { useNavigate } from '@/router' import { Card, CardList } from '@blueprintjs/core' @@ -10,8 +11,7 @@ const OtherPage = () => { return ( <EditorPage - title='Define other information' - description='Add new tools and email addresses to your exercise.' + pageKey={PageNames.OTHER} prevPath='/editor/create/inject-specification' nextPath='/editor/create/final-information' pageVisible={access?.injectsFilled} diff --git a/frontend/src/pages/editor/create/tools.tsx b/frontend/src/pages/editor/create/tools.tsx index e8e7a6a75b0a5ced731a18cec0e689798a1f5a64..a6f288235bbd35b1e6424baef48e667fc417d6fa 100644 --- a/frontend/src/pages/editor/create/tools.tsx +++ b/frontend/src/pages/editor/create/tools.tsx @@ -1,6 +1,7 @@ import EditorPage from '@/editor/EditorPage' import ToolForm from '@/editor/ToolForm' import Tools from '@/editor/Tools' +import { PageNames } from '@/editor/types' import useEditorAccessStorage from '@/editor/useEditorAccessStorage' import { memo } from 'react' @@ -9,8 +10,7 @@ const ToolsPage = () => { return ( <EditorPage - title='Define tools' - description='Description.' + pageKey={PageNames.TOOLS} prevPath='/editor/create/other' nextVisible={false} pageVisible={access?.injectsFilled} diff --git a/frontend/src/views/EditorView/index.tsx b/frontend/src/views/EditorView/index.tsx index 31b1e064b625b7e0ad4a8fa28b4935838ffed488..ad3f1b3347205747dd9e7f9272c944c5b7d9196e 100644 --- a/frontend/src/views/EditorView/index.tsx +++ b/frontend/src/views/EditorView/index.tsx @@ -3,6 +3,7 @@ import type { Section } from '@/components/Sidebar' import Sidebar from '@/components/Sidebar' import useHideButton from '@/components/Sidebar/useHideButton' import Navbar from '@/editor/Navbar' +import { NAVIGATION_CONTENT } from '@/editor/assets/navigationContent' import { db } from '@/editor/indexeddb/db' import { areActivitiesSpecified, @@ -128,7 +129,7 @@ const EditorView: FC<PropsWithChildren> = ({ children }) => { ), }, { - name: 'Steps', + name: NAVIGATION_CONTENT.title, node: !hideLeftBar && <Navbar />, }, ],