Skip to content

Commit 690ffef

Browse files
committed
feat: allow adding custom languages per participant
1 parent 6f35a6d commit 690ffef

File tree

8 files changed

+51
-25
lines changed

8 files changed

+51
-25
lines changed

apps/backend/src/defaults/languages/language.dto.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,7 @@ export class LanguageDto {
2424
entryLanguages: number[];
2525
}
2626
export class LanguageResponseDto extends LanguageDto {}
27-
export class LanguageCreationDto extends OmitType(LanguageDto, ["id", "entryLanguages"]) {}
27+
export class LanguageCreationDto extends OmitType(LanguageDto, ["id", "entryLanguages", "participant"]) {
28+
participant?: number;
29+
}
2830
export class LanguageMutationDto extends PartialType(LanguageCreationDto) {}

apps/backend/src/defaults/languages/languages.controller.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { Body, Controller, Delete, Get, Param, Patch, Post } from "@nestjs/common";
2-
import { ApiOperation, ApiTags, ApiUnprocessableEntityResponse } from "@nestjs/swagger";
1+
import { Body, Controller, Delete, Get, Param, Patch, Post, Query } from "@nestjs/common";
2+
import { ApiOperation, ApiQuery, ApiTags, ApiUnprocessableEntityResponse } from "@nestjs/swagger";
33
import { LanguagesService } from "./languages.service";
44
import { ErrorResponseDto } from "../../common/dto/error.dto";
55
import { Roles } from "../../system/users/roles.decorator";
@@ -19,9 +19,10 @@ export class LanguagesController {
1919
}
2020

2121
@Get()
22+
@ApiQuery({ name: "participantId", required: false, type: Number })
2223
@ApiOperation({ summary: "Get all languages" })
23-
index(): Promise<LanguageResponseDto[]> {
24-
return this.languagesService.findAll();
24+
index(@Query("participantId") participantId?: number): Promise<LanguageResponseDto[]> {
25+
return this.languagesService.findAll(participantId);
2526
}
2627

2728
@Get(":id")

apps/backend/src/defaults/languages/languages.service.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export class LanguagesService {
1414

1515
async create(languageCreationDto: LanguageCreationDto) {
1616
const language = new Language();
17-
language.assign(languageCreationDto);
17+
language.assign(languageCreationDto, { em: this.em });
1818

1919
try {
2020
await this.em.persist(language).flush();
@@ -28,8 +28,12 @@ export class LanguagesService {
2828
return language.toObject();
2929
}
3030

31-
async findAll() {
32-
return (await this.languageRepository.findAll()).map((language) => language.toObject());
31+
async findAll(participantId?: number) {
32+
return (
33+
await this.languageRepository.findAll({
34+
where: participantId ? { $or: [{ participant: null }, { participant: participantId }] } : { participant: null },
35+
})
36+
).map((language) => language.toObject());
3337
}
3438

3539
async findOne(id: number) {

apps/frontend/src/api.gen.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -514,7 +514,7 @@ export interface components {
514514
* @example de-DE
515515
*/
516516
ietfBcp47?: string;
517-
participant?: components["schemas"]["ParticipantDto"];
517+
participant?: number;
518518
};
519519
LanguageResponseDto: {
520520
/**
@@ -546,7 +546,7 @@ export interface components {
546546
* @example de-DE
547547
*/
548548
ietfBcp47?: string;
549-
participant?: components["schemas"]["ParticipantDto"];
549+
participant?: number;
550550
};
551551
ParticipantCreationDto: {
552552
/**
@@ -1424,7 +1424,9 @@ export interface operations {
14241424
};
14251425
LanguagesController_index: {
14261426
parameters: {
1427-
query?: never;
1427+
query?: {
1428+
participantId?: number;
1429+
};
14281430
header?: never;
14291431
path?: never;
14301432
cookie?: never;

apps/frontend/src/components/EntitySelect.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ export function EntitySelect<T extends { id: number }>({ value, onChange, data,
6767
if (value === customValueKey) {
6868
id = await onAddNew!(searchValue);
6969
} else {
70-
id = parseInt(value);
70+
id = +value;
7171
}
7272
onChange?.(id);
7373
combobox.closeDropdown();
Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
import { $api } from "../stores/api";
1+
import { components } from "../api.gen";
22
import { EntitySelect, EntitySelectProps } from "./EntitySelect";
33

4-
type LanguageSelectProps = EntitySelectProps;
4+
type LanguageSelectProps = EntitySelectProps & {
5+
data: components["schemas"]["LanguageDto"][];
6+
};
57

6-
export function LanguageSelect({ value, onChange, ...rest }: LanguageSelectProps) {
7-
const { data } = $api.useQuery("get", "/languages");
8-
9-
return <EntitySelect value={value} onChange={onChange} {...rest} data={data} inputKey="name" />;
8+
export function LanguageSelect({ value, onChange, data, onAddNew, ...rest }: LanguageSelectProps) {
9+
return <EntitySelect value={value} onChange={onChange} onAddNew={onAddNew} {...rest} data={data} inputKey="name" />;
1010
}

apps/frontend/src/components/questionnaire/calendar/EntryForm.tsx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,14 @@ type EntityFormProps = {
3232
onSave: (entity: EntryFormValues) => void;
3333
onDelete?: () => void;
3434
onAddCarer: (value: string) => Promise<number>;
35+
onAddLanguage: (value: string) => Promise<number>;
3536
entry?: Partial<EntryFormValues>;
3637
carers: components["schemas"]["CarerDto"][];
38+
languages: components["schemas"]["LanguageDto"][];
3739
actionLabel: string;
3840
};
3941

40-
export function EntityForm({ onSave, onDelete, onAddCarer, actionLabel, entry, carers }: EntityFormProps) {
42+
export function EntityForm({ onSave, onDelete, onAddCarer, onAddLanguage, actionLabel, entry, carers, languages }: EntityFormProps) {
4143
const t = useStore(messages);
4244
const f = useForm<EntryFormValues>({
4345
initialValues: {
@@ -98,7 +100,13 @@ export function EntityForm({ onSave, onDelete, onAddCarer, actionLabel, entry, c
98100
// TODO: make key either languageId or name of new language entry
99101
<Group key={`entry-${index}`} justify="stretch">
100102
<NumberInput {...f.getInputProps(`entryLanguages.${index}.ratio`)} max={100} min={1} w={80} rightSection="%" />
101-
<LanguageSelect {...f.getInputProps(`entryLanguages.${index}.language`)} flex={1} placeholder={t.labelLanguage} />
103+
<LanguageSelect
104+
data={languages}
105+
onAddNew={onAddLanguage}
106+
{...f.getInputProps(`entryLanguages.${index}.language`)}
107+
flex={1}
108+
placeholder={t.labelLanguage}
109+
/>
102110
{!!index && (
103111
<ActionIcon
104112
variant="light"

apps/frontend/src/routes/_auth/questionnaire/_questionnaire/$id/entries.tsx

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,19 @@ function QuestionnaireEntries() {
5353
const deleteMutation = $api.useMutation("delete", "/entries/{id}");
5454
const { data: questionnaire, refetch } = $api.useSuspenseQuery("get", "/questionnaires/{id}", { params: { path: { id: p.id } } });
5555

56-
const { data: carers } = $api.useQuery("get", "/carers", { params: { query: { participantId: questionnaire.participant?.id } } });
56+
const participantId = questionnaire.participant?.id;
57+
58+
const { data: languages } = $api.useQuery("get", "/languages", { params: { query: { participantId } } });
59+
const createLanguageMutation = $api.useMutation("post", "/languages", {
60+
onSuccess() {
61+
c.refetchQueries($api.queryOptions("get", "/languages", { params: { query: { participantId } } }));
62+
},
63+
});
64+
65+
const { data: carers } = $api.useQuery("get", "/carers", { params: { query: { participantId } } });
5766
const createCarerMutation = $api.useMutation("post", "/carers", {
5867
onSuccess() {
59-
c.refetchQueries($api.queryOptions("get", "/carers"));
68+
c.refetchQueries($api.queryOptions("get", "/carers", { params: { query: { participantId } } }));
6069
},
6170
});
6271

@@ -121,13 +130,13 @@ function QuestionnaireEntries() {
121130
<>
122131
<Modal opened={opened} onClose={close} size="md">
123132
<EntityForm
124-
onAddCarer={(name) =>
125-
createCarerMutation.mutateAsync({ body: { name, participant: questionnaire?.participant?.id } }).then(({ id }) => id)
126-
}
133+
onAddCarer={(name) => createCarerMutation.mutateAsync({ body: { name, participant: participantId } }).then(({ id }) => id)}
134+
onAddLanguage={(name) => createLanguageMutation.mutateAsync({ body: { name, participant: participantId } }).then(({ id }) => id)}
127135
onSave={handleOnSave}
128136
onDelete={entryUpdatingId ? () => handleDelete(entryUpdatingId) : undefined}
129137
entry={entryDraft}
130138
carers={carers ?? []}
139+
languages={languages ?? []}
131140
actionLabel={t.addEntityLabel}
132141
/>
133142
</Modal>

0 commit comments

Comments
 (0)