Skip to content

Commit 80c4bd2

Browse files
#6 Ajouter l'url au forulaire + contraintes d'unicité (#25)
2 parents 548432e + ff5d66f commit 80c4bd2

File tree

13 files changed

+94
-9
lines changed

13 files changed

+94
-9
lines changed

bun.lockb

0 Bytes
Binary file not shown.

messages/en/webcams.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@
1212
}
1313
},
1414
"webcamCreation": {
15-
"title": "Add a new Webcam",
15+
"title": "Submission form for a new webcam",
1616
"nameLabel": "Webcam name",
17+
"urlLabel": "Webcam URL",
1718
"angleOfViewLabel": "Angle of view (in degrees)",
1819
"latitudeLabel": "Latitude",
1920
"longitudeLabel": "Longitude",
@@ -22,7 +23,10 @@
2223
"submitButton": "Add Webcam",
2324
"successMessage": "Webcam successfully created",
2425
"errorMessage": {
25-
"nameRequired": "The name is required",
26+
"fieldRequired": "This field is required",
27+
"nameNotUnique": "This webcam name is already used",
28+
"urlNotUnique": "This webcam URL has already been registered",
29+
"urlInvalid": "The URL is invalid",
2630
"angleOfViewPositive": "The angle of view must be positive"
2731
}
2832
}

messages/fr/webcams.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@
1212
}
1313
},
1414
"webcamCreation": {
15-
"title": "Ajouter une nouvelle Webcam",
15+
"title": "Formulaire de proposition de webcam",
1616
"nameLabel": "Nom de la webcam",
17+
"urlLabel": "URL de la webcam",
1718
"angleOfViewLabel": "Angle de vue (en degrés)",
1819
"latitudeLabel": "Latitude",
1920
"longitudeLabel": "Longitude",
@@ -22,7 +23,10 @@
2223
"submitButton": "Ajouter la Webcam",
2324
"successMessage": "Webcam créée avec succès",
2425
"errorMessage": {
25-
"nameRequired": "Le nom est requis",
26+
"fieldRequired": "Ce champ est requis",
27+
"nameNotUnique": "Ce nom de webcam est déjà utilisé",
28+
"urlNotUnique": "Cette URL de webcam a déjà été enregistrée",
29+
"urlInvalid": "L'URL est invalide",
2630
"angleOfViewPositive": "L'angle de vue doit être positif"
2731
}
2832
}

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@
6161
"tailwindcss-animate": "^1.0.7",
6262
"tsx": "^4.21.0",
6363
"ws": "^8.17.0",
64-
"zod": "^3.23.8"
64+
"zod": "^4.3.6"
6565
},
6666
"devDependencies": {
6767
"@commitlint/cli": "^19.7.1",
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/*
2+
Warnings:
3+
4+
- A unique constraint covering the columns `[url]` on the table `Webcam` will be added. If there are existing duplicate values, this will fail.
5+
6+
*/
7+
-- AlterTable
8+
ALTER TABLE "Webcam" ADD COLUMN "url" TEXT;
9+
10+
-- CreateIndex
11+
CREATE UNIQUE INDEX "Webcam_url_key" ON "Webcam"("url");

prisma/schema.prisma

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ datasource db {
1616
model Webcam {
1717
id String @id @default(cuid())
1818
name String @unique
19+
url String? @unique
1920
angleOfView Float
2021
elevation Int?
2122
latitude Float

src/app/[locale]/webcams/action.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
"use server";
22

33
import { saveNewWebcam } from "@/features/webcams/api/createWebcam";
4+
import {
5+
isWebcamNameUnique,
6+
isWebcamUrlUnique,
7+
} from "@/features/webcams/api/newWebcamChecks";
48

59
import { CreateWebcamInputs, createWebcamSchema } from "./schema";
610
import { WebcamFormState } from "./types";
@@ -12,10 +16,21 @@ export async function createWebcam(
1216
const rawData = Object.fromEntries(formData.entries());
1317

1418
const parsed = createWebcamSchema.safeParse(rawData);
19+
const errors: Record<string, string[]> =
20+
parsed.error?.flatten().fieldErrors ?? {};
1521

16-
if (!parsed.success) {
22+
if (!(await isWebcamNameUnique(formData.get("name") as string))) {
23+
errors.name = ["webcamCreation.errorMessage.nameNotUnique"];
24+
}
25+
26+
if (!(await isWebcamUrlUnique(formData.get("url") as string))) {
27+
errors.url = ["webcamCreation.errorMessage.urlNotUnique"];
28+
}
29+
30+
if (!parsed.success || Object.keys(errors).length > 0) {
1731
return {
18-
errors: parsed.error.flatten().fieldErrors,
32+
createWebcamForm: formData,
33+
errors: errors,
1934
};
2035
}
2136

src/app/[locale]/webcams/schema.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import { z } from "zod";
22

33
export const createWebcamSchema = z.object({
4-
name: z.string().min(1, "webcamCreation.errorMessage.nameRequired"),
4+
name: z.string().min(1, "webcamCreation.errorMessage.fieldRequired"),
5+
6+
url: z.url("webcamCreation.errorMessage.urlInvalid"),
57

68
angleOfView: z.coerce
79
.number()

src/app/[locale]/webcams/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export type WebcamFormState = {
22
success?: boolean;
3+
createWebcamForm?: FormData;
34
errors?: Record<string, string[]>;
45
};

src/app/[locale]/webcams/webcam-form.tsx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ export default function WebcamForm({ action }: Props) {
4747
)}
4848

4949
<TextField
50+
defaultValue={state.createWebcamForm?.get("name") ?? ""}
5051
error={!!state.errors?.name}
5152
helperText={
5253
state.errors?.name?.[0] ? t(state.errors.name[0]) : undefined
@@ -56,6 +57,17 @@ export default function WebcamForm({ action }: Props) {
5657
/>
5758

5859
<TextField
60+
defaultValue={state.createWebcamForm?.get("url") ?? ""}
61+
error={!!state.errors?.url}
62+
helperText={
63+
state.errors?.url?.[0] ? t(state.errors.url[0]) : undefined
64+
}
65+
label={t("webcamCreation.urlLabel")}
66+
name="url"
67+
/>
68+
69+
<TextField
70+
defaultValue={state.createWebcamForm?.get("angleOfView") ?? ""}
5971
error={!!state.errors?.angleOfView}
6072
helperText={
6173
state.errors?.angleOfView?.[0]
@@ -68,6 +80,7 @@ export default function WebcamForm({ action }: Props) {
6880
/>
6981

7082
<TextField
83+
defaultValue={state.createWebcamForm?.get("latitude") ?? ""}
7184
error={!!state.errors?.latitude}
7285
helperText={state.errors?.latitude?.[0]}
7386
label={t("webcamCreation.latitudeLabel")}
@@ -76,6 +89,7 @@ export default function WebcamForm({ action }: Props) {
7689
/>
7790

7891
<TextField
92+
defaultValue={state.createWebcamForm?.get("longitude") ?? ""}
7993
error={!!state.errors?.longitude}
8094
helperText={state.errors?.longitude?.[0]}
8195
label={t("webcamCreation.longitudeLabel")}
@@ -84,6 +98,7 @@ export default function WebcamForm({ action }: Props) {
8498
/>
8599

86100
<TextField
101+
defaultValue={state.createWebcamForm?.get("elevation") ?? ""}
87102
error={!!state.errors?.elevation}
88103
helperText={state.errors?.elevation?.[0]}
89104
label={t("webcamCreation.elevationLabel")}
@@ -92,6 +107,7 @@ export default function WebcamForm({ action }: Props) {
92107
/>
93108

94109
<TextField
110+
defaultValue={state.createWebcamForm?.get("refreshSeconds") ?? ""}
95111
error={!!state.errors?.refreshSeconds}
96112
helperText={state.errors?.refreshSeconds?.[0]}
97113
label={t("webcamCreation.refreshSecondsLabel")}

0 commit comments

Comments
 (0)