Skip to content

Commit b31b635

Browse files
authored
Merge pull request #1319 from david-roper/adjust-age-limit
Adjust age limit
2 parents a850d30 + a81cc90 commit b31b635

File tree

4 files changed

+87
-17
lines changed

4 files changed

+87
-17
lines changed

apps/api/prisma/schema.prisma

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ type GroupSettings {
9999
idValidationRegex String?
100100
idValidationRegexErrorMessage ErrorMessage?
101101
subjectIdDisplayLength Int?
102+
minimumAge Int?
102103
}
103104

104105
model Group {

apps/web/src/components/StartSessionForm/StartSessionForm.tsx

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,6 @@ import { z } from 'zod/v4';
1515

1616
const currentDate = new Date();
1717

18-
const EIGHTEEN_YEARS = 568025136000; // milliseconds
19-
20-
const MIN_DATE_OF_BIRTH = new Date(currentDate.getTime() - EIGHTEEN_YEARS);
21-
2218
type StartSessionFormData = {
2319
sessionDate: Date;
2420
sessionType: 'IN_PERSON' | 'RETROSPECTIVE';
@@ -46,6 +42,10 @@ export const StartSessionForm = ({
4642
onSubmit
4743
}: StartSessionFormProps) => {
4844
const { resolvedLanguage, t } = useTranslation();
45+
const minDateOfBirth = currentGroup?.settings.minimumAge
46+
? new Date(currentDate.getTime() - currentGroup.settings.minimumAge * 31556952000)
47+
: undefined;
48+
4949
return (
5050
<Form
5151
preventResetValuesOnReset
@@ -177,8 +177,19 @@ export const StartSessionForm = ({
177177
.optional(),
178178
subjectDateOfBirth: z
179179
.date()
180-
.max(MIN_DATE_OF_BIRTH, { message: t('session.errors.mustBeAdult') })
181-
.optional(),
180+
.optional()
181+
.refine(
182+
(date) => {
183+
if (!date || !minDateOfBirth) return true;
184+
return date <= minDateOfBirth;
185+
},
186+
{
187+
message: t({
188+
en: `Subject must be above age of ${currentGroup?.settings.minimumAge}`,
189+
fr: `Le sujet doit être âgé de plus de ${currentGroup?.settings.minimumAge}`
190+
})
191+
}
192+
),
182193
subjectSex: z.enum(['MALE', 'FEMALE']).optional(),
183194
sessionType: $SessionType.exclude(['REMOTE']),
184195
sessionDate: z

apps/web/src/routes/_app/group/manage.tsx

Lines changed: 68 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@ type ManageGroupFormProps = {
3232
accessibleInteractiveInstrumentIds: Set<string>;
3333
defaultIdentificationMethod?: SubjectIdentificationMethod;
3434
idValidationRegex?: null | string;
35-
subjectIdDisplayLength?: number;
35+
minimumAge?: null | number;
36+
minimumAgeApplied?: boolean | null;
37+
subjectIdDisplayLength?: null | number;
3638
};
3739
};
3840
onSubmit: (data: Partial<UpdateGroupData>) => Promisable<any>;
@@ -86,6 +88,40 @@ const ManageGroupForm = ({ data, onSubmit, readOnly }: ManageGroupFormProps) =>
8688
fr: "Paramètres d'affichage"
8789
})
8890
},
91+
{
92+
fields: {
93+
minimumAgeApplied: {
94+
kind: 'boolean',
95+
label: t({
96+
en: 'Apply Minimum Age For Subjects',
97+
fr: 'Appliquer un âge minimum aux sujets'
98+
}),
99+
variant: 'radio'
100+
},
101+
// eslint-disable-next-line perfectionist/sort-objects
102+
minimumAge: {
103+
deps: ['minimumAgeApplied'],
104+
kind: 'dynamic',
105+
render: (data) => {
106+
if (data.minimumAgeApplied) {
107+
return {
108+
kind: 'number',
109+
label: t({
110+
en: 'Minimum Age',
111+
fr: "L'âge minimum"
112+
}),
113+
variant: 'input'
114+
};
115+
}
116+
return null;
117+
}
118+
}
119+
},
120+
title: t({
121+
en: 'Age Limit Settings',
122+
fr: "Paramètres de l'âge"
123+
})
124+
},
89125
{
90126
fields: {
91127
defaultIdentificationMethod: {
@@ -150,15 +186,32 @@ const ManageGroupForm = ({ data, onSubmit, readOnly }: ManageGroupFormProps) =>
150186
initialValues={initialValues}
151187
preventResetValuesOnReset={true}
152188
readOnly={readOnly}
153-
validationSchema={z.object({
154-
accessibleFormInstrumentIds: z.set(z.string()),
155-
accessibleInteractiveInstrumentIds: z.set(z.string()),
156-
defaultIdentificationMethod: $SubjectIdentificationMethod.optional(),
157-
idValidationRegex: $RegexString.optional(),
158-
idValidationRegexErrorMessageEn: z.string().optional(),
159-
idValidationRegexErrorMessageFr: z.string().optional(),
160-
subjectIdDisplayLength: z.number().int().min(1)
161-
})}
189+
validationSchema={z
190+
.object({
191+
accessibleFormInstrumentIds: z.set(z.string()),
192+
accessibleInteractiveInstrumentIds: z.set(z.string()),
193+
defaultIdentificationMethod: $SubjectIdentificationMethod.optional(),
194+
idValidationRegex: $RegexString.optional(),
195+
idValidationRegexErrorMessageEn: z.string().optional(),
196+
idValidationRegexErrorMessageFr: z.string().optional(),
197+
minimumAge: z.number().int().positive().optional(),
198+
minimumAgeApplied: z.boolean().optional(),
199+
subjectIdDisplayLength: z.number().int().min(1).optional()
200+
})
201+
.check((ctx) => {
202+
if (ctx.value.minimumAgeApplied && !ctx.value.minimumAge) {
203+
ctx.issues.push({
204+
code: 'custom',
205+
input: ctx.value.minimumAge,
206+
message: t({
207+
en: 'Please enter an age',
208+
fr: "Entrez un âge s'il vous plait"
209+
}),
210+
path: ['minimumAge']
211+
});
212+
}
213+
return;
214+
})}
162215
onSubmit={(data) => {
163216
void onSubmit({
164217
accessibleInstrumentIds: [...data.accessibleFormInstrumentIds, ...data.accessibleInteractiveInstrumentIds],
@@ -169,6 +222,7 @@ const ManageGroupForm = ({ data, onSubmit, readOnly }: ManageGroupFormProps) =>
169222
en: data.idValidationRegexErrorMessageEn,
170223
fr: data.idValidationRegexErrorMessageFr
171224
},
225+
minimumAge: data.minimumAgeApplied ? data.minimumAge : null,
172226
subjectIdDisplayLength: data.subjectIdDisplayLength
173227
}
174228
});
@@ -207,7 +261,10 @@ const RouteComponent = () => {
207261
defaultIdentificationMethod,
208262
idValidationRegex: settings?.idValidationRegex,
209263
idValidationRegexErrorMessageEn: settings?.idValidationRegexErrorMessage?.en,
210-
idValidationRegexErrorMessageFr: settings?.idValidationRegexErrorMessage?.fr
264+
idValidationRegexErrorMessageFr: settings?.idValidationRegexErrorMessage?.fr,
265+
minimumAge: settings?.minimumAge,
266+
minimumAgeApplied: typeof settings?.minimumAge === 'number',
267+
subjectIdDisplayLength: settings?.subjectIdDisplayLength
211268
};
212269
for (const instrument of availableInstruments) {
213270
if (instrument.kind === 'FORM') {

packages/schemas/src/group/group.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export const $GroupSettings = z.object({
1313
fr: z.string().nullish()
1414
})
1515
.nullish(),
16+
minimumAge: z.number().int().positive().nullish(),
1617
subjectIdDisplayLength: z.number().nullish()
1718
});
1819

0 commit comments

Comments
 (0)