i18n support added to all form validations

This commit is contained in:
2024-02-17 07:28:47 +01:00
parent 1da6479c80
commit 30b3da9c31
4 changed files with 38 additions and 30 deletions

View File

@@ -1,11 +1,20 @@
import {notFound} from 'next/navigation'; import {notFound} from 'next/navigation';
import {getRequestConfig} from 'next-intl/server'; import {getRequestConfig} from 'next-intl/server';
import { Formats, TranslationValues } from 'next-intl';
// Can be imported from a shared config // Can be imported from a shared config
export const locales = ['en', 'hr']; export const locales = ['en', 'hr'];
export const defaultLocale = 'en'; export const defaultLocale = 'en';
/** Templating function type as returned by `useTemplate` and `getTranslations` */
export type IntlTemplateFn =
// this function type if returned by `useTransations`
(<TargetKey extends any>(key: TargetKey, values?: TranslationValues | undefined, formats?: Partial<Formats> | undefined) => string) |
// this functon type if returned by `getTranslations`
(<TargetKey extends any>(key: [TargetKey] extends [never] ? string : TargetKey, values?: TranslationValues | undefined, formats?: Partial<Formats> | undefined) => string);
export default getRequestConfig(async ({locale}) => { export default getRequestConfig(async ({locale}) => {
// Validate that the incoming `locale` parameter is valid // Validate that the incoming `locale` parameter is valid
if (!locales.includes(locale as any)) notFound(); if (!locales.includes(locale as any)) notFound();

View File

@@ -7,7 +7,8 @@ import { ObjectId } from 'mongodb';
import { withUser } from '@/app/lib/auth'; import { withUser } from '@/app/lib/auth';
import { AuthenticatedUser } from '../types/next-auth'; import { AuthenticatedUser } from '../types/next-auth';
import { gotoHome } from './navigationActions'; import { gotoHome } from './navigationActions';
import { Formats, TranslationValues, useTranslations } from "next-intl"; import { getTranslations } from "next-intl/server";
import { IntlTemplateFn } from '@/app/i18n';
export type State = { export type State = {
errors?: { errors?: {
@@ -19,10 +20,11 @@ export type State = {
message?:string | null; message?:string | null;
} }
type IntlTemplate = <TargetKey extends any>(key: TargetKey, values?: TranslationValues | undefined, formats?: Partial<Formats> | undefined) => string; /**
* Schema for validating bill form fields
* @description this is defined as factory function so that it can be used with the next-intl library
const FormSchema = (t:IntlTemplate) => z.object({ */
const FormSchema = (t:IntlTemplateFn) => z.object({
_id: z.string(), _id: z.string(),
billName: z.coerce.string().min(1, t("bill-name-required")), billName: z.coerce.string().min(1, t("bill-name-required")),
billNotes: z.string(), billNotes: z.string(),
@@ -65,10 +67,6 @@ const FormSchema = (t:IntlTemplate) => z.object({
}), }),
}); });
parseFloat
const UpdateBill = ;
/** /**
* converts the file to a format stored in the database * converts the file to a format stored in the database
* @param billAttachment * @param billAttachment
@@ -117,10 +115,10 @@ export const updateOrAddBill = withUser(async (user:AuthenticatedUser, locationI
const { id: userId } = user; const { id: userId } = user;
const t = useTranslations("bill-edit-form.validation"); const t = await getTranslations("bill-edit-form.validation");
// FormSchema // FormSchema
const validatedFields = UpdateBill(t) const validatedFields = FormSchema(t)
.omit({ _id: true }) .omit({ _id: true })
.safeParse({ .safeParse({
billName: formData.get('billName'), billName: formData.get('billName'),

View File

@@ -8,7 +8,8 @@ import { withUser } from '@/app/lib/auth';
import { AuthenticatedUser } from '../types/next-auth'; import { AuthenticatedUser } from '../types/next-auth';
import { gotoHome } from './navigationActions'; import { gotoHome } from './navigationActions';
import { unstable_noStore as noStore } from 'next/cache'; import { unstable_noStore as noStore } from 'next/cache';
import { asyncTimeout } from '../asyncTimeout'; import { IntlTemplateFn } from '@/app/i18n';
import { getTranslations } from "next-intl/server";
export type State = { export type State = {
errors?: { errors?: {
@@ -18,13 +19,17 @@ export type State = {
message?:string | null; message?:string | null;
}; };
const FormSchema = z.object({ /**
* Schema for validating location form fields
* @description this is defined as factory function so that it can be used with the next-intl library
*/
const FormSchema = (t:IntlTemplateFn) => z.object({
_id: z.string(), _id: z.string(),
locationName: z.coerce.string().min(1, "Location Name is required."), locationName: z.coerce.string().min(1, t("location-name-required")),
locationNotes: z.string(), locationNotes: z.string(),
}); })
// dont include the _id field in the response
const UpdateLocation = FormSchema.omit({ _id: true }); .omit({ _id: true });
/** /**
* Server-side action which adds or updates a bill * Server-side action which adds or updates a bill
@@ -37,7 +42,9 @@ export const updateOrAddLocation = withUser(async (user:AuthenticatedUser, locat
noStore(); noStore();
const validatedFields = UpdateLocation.safeParse({ const t = await getTranslations("location-edit-form.validation");
const validatedFields = FormSchema(t).safeParse({
locationName: formData.get('locationName'), locationName: formData.get('locationName'),
locationNotes: formData.get('locationNotes'), locationNotes: formData.get('locationNotes'),
}); });
@@ -84,8 +91,6 @@ export const updateOrAddLocation = withUser(async (user:AuthenticatedUser, locat
}); });
} }
// await asyncTimeout(1000);
if(yearMonth) await gotoHome(yearMonth); if(yearMonth) await gotoHome(yearMonth);
return { return {
@@ -124,8 +129,6 @@ export const fetchAllLocations = withUser(async (user:AuthenticatedUser, year:nu
}) })
.toArray(); .toArray();
// await asyncTimeout(1000);
return(locations) return(locations)
}) })
@@ -154,8 +157,6 @@ export const fetchLocationById = withUser(async (user:AuthenticatedUser, locatio
return(null); return(null);
} }
// await asyncTimeout(1000);
return(billLocation); return(billLocation);
}) })
@@ -170,7 +171,5 @@ export const deleteLocationById = withUser(async (user:AuthenticatedUser, locati
// find a location with the given locationID // find a location with the given locationID
const post = await dbClient.collection<BillingLocation>("lokacije").deleteOne({ _id: locationID, userId }); const post = await dbClient.collection<BillingLocation>("lokacije").deleteOne({ _id: locationID, userId });
// await asyncTimeout(1000);
await gotoHome(yearMonth) await gotoHome(yearMonth)
}) })

View File

@@ -95,7 +95,9 @@
"notes-placeholder": "Notes", "notes-placeholder": "Notes",
"save-button": "Save", "save-button": "Save",
"cancel-button": "Cancel", "cancel-button": "Cancel",
"delete-tooltip": "Delete realestate" "delete-tooltip": "Delete realestate",
"validation": {
} "location-name-required": "Relaestate name is required"
}
}
} }