From d5c15d4d945a83e16e7de2ee8137aac6702e03f1 Mon Sep 17 00:00:00 2001 From: Camillo bucciarelli Date: Fri, 9 Aug 2024 17:09:06 +0200 Subject: [PATCH 1/2] BO44 --- astro.config.mjs | 22 +- src/constants/i18n.ts | 5 + src/data/firestore/common/create.spec.ts | 46 ++-- src/data/firestore/common/create.ts | 24 +- src/data/firestore/common/delete.spec.ts | 35 +-- src/data/firestore/common/get-by-id.spec.ts | 5 +- src/data/firestore/common/test-model.ts | 34 ++- src/data/firestore/common/update.spec.ts | 5 +- .../converters/localization-converter.spec.ts | 252 ++++++++++++++++++ .../docs/converters/localization-converter.ts | 73 +++++ src/data/firestore/docs/localized-field.ts | 14 + .../firestore/docs/model-document-mapper.ts | 24 ++ src/data/firestore/docs/utils.ts | 7 + src/data/firestore/user.spec.ts | 5 +- src/data/firestore/user.ts | 2 +- src/data/model-document-mapper.ts | 9 - .../localization/localization.schema.ts | 8 + src/models/localization/localization.type.ts | 7 + src/models/pagination/pagination.type.ts | 3 +- src/models/user/user.type.ts | 2 +- src/shared/Dummy/dummy.test.ts | 5 - 21 files changed, 489 insertions(+), 98 deletions(-) create mode 100644 src/constants/i18n.ts create mode 100644 src/data/firestore/docs/converters/localization-converter.spec.ts create mode 100644 src/data/firestore/docs/converters/localization-converter.ts create mode 100644 src/data/firestore/docs/localized-field.ts create mode 100644 src/data/firestore/docs/model-document-mapper.ts create mode 100644 src/data/firestore/docs/utils.ts delete mode 100644 src/data/model-document-mapper.ts create mode 100644 src/models/localization/localization.schema.ts create mode 100644 src/models/localization/localization.type.ts delete mode 100644 src/shared/Dummy/dummy.test.ts diff --git a/astro.config.mjs b/astro.config.mjs index f134d232..880642ba 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -4,15 +4,21 @@ import tailwind from "@astrojs/tailwind"; import nodejs from "@astrojs/node"; import astroI18next from "astro-i18next"; import icon from "astro-icon"; +import { defaultLanguage, supportedLanguages } from "~/constants/i18n.js"; // https://astro.build/config export default defineConfig({ site: "https://devfest.gdgpescara.it", - integrations: [icon({ - include: { - mdi: ["*"], // (Default) Loads entire Material Design Icon set - }, - }),react(), tailwind(), astroI18next()], + integrations: [ + icon({ + include: { + mdi: ["*"], // (Default) Loads entire Material Design Icon set + }, + }), + react(), + tailwind(), + astroI18next(), + ], output: "hybrid", adapter: nodejs({ mode: "standalone", @@ -21,10 +27,10 @@ export default defineConfig({ domains: ["via.placeholder.com"], }, i18n: { - defaultLocale: "en", - locales: ["en", "it"], + defaultLocale: defaultLanguage, + locales: supportedLanguages, fallback: { - it: "en", + it: defaultLanguage, }, routingStrategy: "prefix-other-locales", }, diff --git a/src/constants/i18n.ts b/src/constants/i18n.ts new file mode 100644 index 00000000..1d0e015b --- /dev/null +++ b/src/constants/i18n.ts @@ -0,0 +1,5 @@ +export const defaultLanguage = "en" as const; + +export const supportedLanguages = ["it", "en"] as const; + +export type SupportedLanguages = (typeof supportedLanguages)[number]; diff --git a/src/data/firestore/common/create.spec.ts b/src/data/firestore/common/create.spec.ts index acb7786a..a807a1cd 100644 --- a/src/data/firestore/common/create.spec.ts +++ b/src/data/firestore/common/create.spec.ts @@ -1,7 +1,7 @@ -import { test, describe, expect } from "vitest"; -import { createDocument } from "./create"; -import { getDocumentById } from "./get-by-id"; -import { testConverter, type TestDoc, type TestModel } from "./test-model"; +import { describe, expect, test } from "vitest"; +import createDocument from "./create"; +import { defaultLanguage } from "~/constants/i18n"; +import {testConverter, type TestDoc, type TestModel} from "./test-model"; import type { FirestoreDataConverter } from "firebase-admin/firestore"; const testCollection = "create-test"; @@ -11,29 +11,18 @@ describe("Create a new document", () => { const modelToSave: TestModel = { lastUpdate: new Date("2024-01-01"), name: "Test Document", + description: "Test description", }; const result = await createDocument( testCollection, testConverter, modelToSave, + defaultLanguage, ); expect(result).toMatchObject({ status: "success", data: expect.any(String), }); - - const getResult = await getDocumentById( - testCollection, - testConverter, - result.data as string, - ); - expect(getResult).toMatchObject({ - status: "success", - data: expect.objectContaining({ - ...modelToSave, - id: result.data, - }), - }); }); test("Should return an error if id is present", async () => { @@ -46,6 +35,7 @@ describe("Create a new document", () => { testCollection, testConverter, modelToSave, + defaultLanguage, ); expect(result).toMatchObject({ status: "error", @@ -73,6 +63,7 @@ describe("Create a new document", () => { testCollection, fakeConverter, modelToSave, + defaultLanguage, ); expect(result).toMatchObject({ status: "error", @@ -93,6 +84,7 @@ describe("Create a new document", () => { testCollection, testConverter, modelToSave, + defaultLanguage, ); expect(result).toMatchObject({ status: "error", @@ -102,4 +94,24 @@ describe("Create a new document", () => { }, }); }); + + test("Should return an error if passed language is not default one", async () => { + const modelToSave: TestModel = { + lastUpdate: new Date("2024-01-01"), + name: "Test Document", + }; + const result = await createDocument( + testCollection, + testConverter, + modelToSave, + "it", + ); + expect(result).toMatchObject({ + status: "error", + data: { + code: `${testCollection}/create-error:default-language-is-required`, + message: "Default language is required", + }, + }); + }); }); diff --git a/src/data/firestore/common/create.ts b/src/data/firestore/common/create.ts index 81a98bc2..6c277d63 100644 --- a/src/data/firestore/common/create.ts +++ b/src/data/firestore/common/create.ts @@ -1,12 +1,10 @@ -import type { - DocumentData, - FirestoreDataConverter, -} from "firebase-admin/firestore"; import { firestoreInstance } from "~/firebase/server"; import type { BaseModel } from "~/models/base-model"; import type { ServerResponse } from "~/models/server-response/server-response.type"; +import { defaultLanguage, type SupportedLanguages } from "~/constants/i18n"; +import type {DocumentData, FirestoreDataConverter} from "firebase-admin/firestore"; -export const createDocument = async < +const createDocument = async < M extends BaseModel, D extends DocumentData, C extends string, @@ -14,13 +12,25 @@ export const createDocument = async < collection: C, converter: FirestoreDataConverter, model: M, + currentLanguage: SupportedLanguages, ): Promise< ServerResponse< string, - `${C}/create-error` | `${C}/create-error:id-is-present` + | `${C}/create-error` + | `${C}/create-error:id-is-present` + | `${C}/create-error:default-language-is-required` > > => { try { + if (currentLanguage !== defaultLanguage) { + return { + status: "error", + data: { + code: `${collection}/create-error:default-language-is-required`, + message: "Default language is required", + }, + }; + } if (model.id) { return { status: "error", @@ -49,3 +59,5 @@ export const createDocument = async < }; } }; + +export default createDocument; diff --git a/src/data/firestore/common/delete.spec.ts b/src/data/firestore/common/delete.spec.ts index 1babd5fd..ac8157de 100644 --- a/src/data/firestore/common/delete.spec.ts +++ b/src/data/firestore/common/delete.spec.ts @@ -1,8 +1,8 @@ import { describe, expect, test } from "vitest"; import { deleteDocument } from "./delete"; -import { createDocument } from "./create"; -import { getDocumentById } from "./get-by-id"; import { testConverter, type TestModel } from "./test-model"; +import createDocument from "./create"; +import { defaultLanguage } from "~/constants/i18n"; const testCollection = "delete-test"; @@ -17,22 +17,9 @@ describe("deleteDocument", () => { testCollection, testConverter, modelToSave, + defaultLanguage, ); - const get = await getDocumentById( - testCollection, - testConverter, - result.data as string, - ); - - expect(get).toMatchObject({ - status: "success", - data: expect.objectContaining({ - ...modelToSave, - id: result.data, - }), - }); - const deleteResult = await deleteDocument( testCollection, result.data as string, @@ -42,22 +29,6 @@ describe("deleteDocument", () => { status: "success", data: null, }); - - const getAfterDelete = await getDocumentById( - testCollection, - testConverter, - result.data as string, - ); - - expect(getAfterDelete).toMatchObject({ - status: "error", - data: { - code: `${testCollection}/get-by-id-error:not-found`, - message: `Document with id ${ - result.data as string - } not found in collection delete-test`, - }, - }); }); test("should return an error if id is missing", async () => { diff --git a/src/data/firestore/common/get-by-id.spec.ts b/src/data/firestore/common/get-by-id.spec.ts index 5d7477db..297af498 100644 --- a/src/data/firestore/common/get-by-id.spec.ts +++ b/src/data/firestore/common/get-by-id.spec.ts @@ -1,8 +1,9 @@ import { describe, expect, test } from "vitest"; -import { createDocument } from "./create"; import { getDocumentById } from "./get-by-id"; import { testConverter, type TestDoc, type TestModel } from "./test-model"; import type { FirestoreDataConverter } from "firebase-admin/firestore"; +import createDocument from "./create"; +import { defaultLanguage } from "~/constants/i18n"; const testCollection = "get-by-id-test"; @@ -17,6 +18,7 @@ describe("Get by id", () => { testCollection, testConverter, modelToSave, + defaultLanguage, ); const get = await getDocumentById( @@ -84,6 +86,7 @@ describe("Get by id", () => { testCollection, testConverter, modelToSave, + defaultLanguage, ); const fakeConverter: FirestoreDataConverter = { diff --git a/src/data/firestore/common/test-model.ts b/src/data/firestore/common/test-model.ts index 662c2481..81779c44 100644 --- a/src/data/firestore/common/test-model.ts +++ b/src/data/firestore/common/test-model.ts @@ -1,31 +1,37 @@ +import type {LocalizedFirestoreDocument} from "~/data/firestore/docs/model-document-mapper"; +import {type FirestoreDataConverter, type QueryDocumentSnapshot, Timestamp} from "firebase-admin/firestore"; import { - QueryDocumentSnapshot, - Timestamp, - type FirestoreDataConverter, -} from "firebase-admin/firestore"; -import type { FirestoreDocument } from "~/data/model-document-mapper"; + localizedFieldFromFirestore, + localizedFieldToFirestore +} from "~/data/firestore/docs/converters/localization-converter.ts"; +import omit from "~/data/firestore/docs/utils.ts"; export type TestModel = { id?: string; name: string; + description?: string; lastUpdate: Date; }; -export type TestDoc = FirestoreDocument; +type TestDocLocalizedFields = "description"; + +export type TestDoc = LocalizedFirestoreDocument export const testConverter: FirestoreDataConverter = { - toFirestore: (company: TestModel): TestDoc => { - return { - ...company, - lastUpdate: Timestamp.fromDate(company.lastUpdate), + toFirestore: (model: TestModel): TestDoc => { + const rest = omit(model, ["id", "description"]); + const doc: TestDoc = { + ...rest, + lastUpdate: Timestamp.fromDate(model.lastUpdate), }; + return localizedFieldToFirestore(model, "en", ["description"], doc); }, fromFirestore: (snapshot: QueryDocumentSnapshot): TestModel => { const data = snapshot.data(); + const model = localizedFieldFromFirestore(snapshot, "en", ["description"]); return { - id: snapshot.id, - ...data, + ...model, lastUpdate: data.lastUpdate.toDate(), - } as TestModel; + }; }, -}; +}; \ No newline at end of file diff --git a/src/data/firestore/common/update.spec.ts b/src/data/firestore/common/update.spec.ts index 0b80c6ad..c5e9a2dd 100644 --- a/src/data/firestore/common/update.spec.ts +++ b/src/data/firestore/common/update.spec.ts @@ -1,9 +1,10 @@ import { test, describe, expect } from "vitest"; import { updateDocument } from "./update"; import { getDocumentById } from "./get-by-id"; -import { createDocument } from "./create"; import { testConverter, type TestDoc, type TestModel } from "./test-model"; import type { FirestoreDataConverter } from "firebase-admin/firestore"; +import createDocument from "./create"; +import { defaultLanguage } from "~/constants/i18n"; const testCollection = "update-test"; @@ -18,6 +19,7 @@ describe("Update a new document", () => { testCollection, testConverter, modelToSave, + defaultLanguage, ); const modelToUpdate = { @@ -88,6 +90,7 @@ describe("Update a new document", () => { testCollection, testConverter, modelToSave, + defaultLanguage, ); const modelToUpdate = { diff --git a/src/data/firestore/docs/converters/localization-converter.spec.ts b/src/data/firestore/docs/converters/localization-converter.spec.ts new file mode 100644 index 00000000..f8a988f1 --- /dev/null +++ b/src/data/firestore/docs/converters/localization-converter.spec.ts @@ -0,0 +1,252 @@ +import { beforeEach, describe, expect, it, vi } from "vitest"; +import { defaultLanguage, type SupportedLanguages } from "~/constants/i18n"; +import type { BaseModel } from "~/models/base-model"; +import type { LocalizedFirestoreDocument } from "~/data/firestore/docs/model-document-mapper"; +import type { + DocumentData, + QueryDocumentSnapshot, +} from "firebase-admin/firestore"; + +import type { LocalizedField } from "~/data/firestore/docs/localized-field"; +import { + localizedFieldFromFirestore, + localizedFieldToFirestore, +} from "~/data/firestore/docs/converters/localization-converter.ts"; + +type TestModel = BaseModel & { + title: string; + description: string; + subtitle?: string; +}; + +type TestLocalizedFields = "title" | "subtitle"; + +type TestDocument = LocalizedFirestoreDocument; + +function createSimpleMockQueryDocumentSnapshot( + id: string, + data: T, +): QueryDocumentSnapshot { + return { + id, + data: vi.fn(() => data), + ref: { id } as any, + metadata: { hasPendingWrites: false, fromCache: false }, + } as unknown as QueryDocumentSnapshot; +} + +describe("localizedFieldToFirestore", () => { + let model: TestModel; + let currentDocument: TestDocument; + const localizedFields: TestLocalizedFields[] = ["title"]; + + beforeEach(() => { + model = { + id: "123", + title: "New Title", + description: "New Description", + }; + currentDocument = { + id: "123", + title: { en: "Old Title", it: "Titolo Vecchio" } as LocalizedField, + description: "Old Description", + }; + }); + + it("should correctly convert a model to a Firestore document", () => { + const result = localizedFieldToFirestore( + model, + "en", + localizedFields, + currentDocument, + ); + expect(result).toEqual({ + id: "123", + title: { en: "New Title", it: "Titolo Vecchio" }, + description: "New Description", + }); + }); + + it("should add a new language if it does not exist in the current document", () => { + const result = localizedFieldToFirestore( + model, + "fr" as SupportedLanguages, + localizedFields, + currentDocument, + ); + expect(result.title as LocalizedField).toHaveProperty("fr", "New Title"); + }); + + it("should throw an error when trying to set default language to empty string", () => { + model.title = ""; + expect(() => + localizedFieldToFirestore( + model, + defaultLanguage, + localizedFields, + currentDocument, + ), + ).toThrow( + `Cannot set default language (${defaultLanguage}) to an empty string for field title`, + ); + }); + + it("should throw an error when a localized field in the model is not a string", () => { + (model as any).title = 42; + expect(() => + localizedFieldToFirestore(model, "en", localizedFields, currentDocument), + ).toThrow("Field title must be a string in the model"); + }); + + it("should handle multiple localized fields", () => { + const multiModel: TestModel = { ...model, subtitle: "New Subtitle" }; + const multiDocument: TestDocument = { + ...currentDocument, + subtitle: { + en: "Old Subtitle", + it: "Sottotitolo Vecchio", + } as LocalizedField, + }; + const multiLocalizedFields: TestLocalizedFields[] = ["title", "subtitle"]; + + const result = localizedFieldToFirestore( + multiModel, + "en", + multiLocalizedFields, + multiDocument, + ); + expect(result).toEqual({ + id: "123", + title: { en: "New Title", it: "Titolo Vecchio" }, + subtitle: { en: "New Subtitle", it: "Sottotitolo Vecchio" }, + description: "New Description", + }); + }); + + it("should not modify non-localized fields", () => { + const result = localizedFieldToFirestore( + model, + "en", + localizedFields, + currentDocument, + ); + expect(result.description).toBe("New Description"); + }); +}); + +describe("localizedFieldFromFirestore", () => { + const localizedFields: TestLocalizedFields[] = ["title"]; + + it("should correctly convert a Firestore document to a model", async () => { + const firestoreData = { + id: "123", + title: { en: "English Title", it: "Titolo Italiano" } as LocalizedField, + description: "Some Description", + }; + + const mockSnapshot = createSimpleMockQueryDocumentSnapshot( + "123", + firestoreData, + ); + + const result = localizedFieldFromFirestore( + mockSnapshot, + "en", + localizedFields, + ); + expect(result).toEqual({ + id: "123", + title: "English Title", + description: "Some Description", + }); + }); + + it("should use the current language value if available", () => { + const firestoreData = { + id: "123", + title: { en: "English Title", it: "Titolo Italiano" } as LocalizedField, + description: "Some Description", + }; + const mockSnapshot = createSimpleMockQueryDocumentSnapshot( + "123", + firestoreData, + ); + + const result = localizedFieldFromFirestore( + mockSnapshot, + "it", + localizedFields, + ); + expect(result.title).toBe("Titolo Italiano"); + }); + + it("should handle non-localized fields correctly", () => { + const firestoreData = { + id: "123", + title: { en: "English Title", it: "Titolo Italiano" } as LocalizedField, + description: "Some Description", + }; + const mockSnapshot = createSimpleMockQueryDocumentSnapshot( + "123", + firestoreData, + ); + + const result = localizedFieldFromFirestore( + mockSnapshot, + "en", + localizedFields, + ); + expect(result.description).toBe("Some Description"); + }); + + it("should return undefined for a language that does not exist in the localized field", () => { + const firestoreData = { + id: "123", + title: { en: "English Title" } as LocalizedField, + description: "Some Description", + }; + const mockSnapshot = createSimpleMockQueryDocumentSnapshot( + "123", + firestoreData, + ); + + const result = localizedFieldFromFirestore( + mockSnapshot, + "it" as SupportedLanguages, + localizedFields, + ); + expect(result.title).toBeUndefined(); + }); + + it("should handle multiple localized fields", () => { + const firestoreData = { + id: "123", + title: { en: "English Title", it: "Titolo Italiano" } as LocalizedField, + description: "Some Description", + }; + const multiData: TestDocument = { + ...firestoreData, + subtitle: { + en: "English Subtitle", + it: "Sottotitolo Italiano", + } as LocalizedField, + }; + const mockSnapshot = createSimpleMockQueryDocumentSnapshot( + "123", + multiData, + ); + const multiLocalizedFields: TestLocalizedFields[] = ["title", "subtitle"]; + + const result = localizedFieldFromFirestore( + mockSnapshot, + "it", + multiLocalizedFields, + ); + expect(result).toEqual({ + id: "123", + title: "Titolo Italiano", + subtitle: "Sottotitolo Italiano", + description: "Some Description", + }); + }); +}); diff --git a/src/data/firestore/docs/converters/localization-converter.ts b/src/data/firestore/docs/converters/localization-converter.ts new file mode 100644 index 00000000..b3aa841e --- /dev/null +++ b/src/data/firestore/docs/converters/localization-converter.ts @@ -0,0 +1,73 @@ +import { defaultLanguage, type SupportedLanguages } from "~/constants/i18n"; +import type { QueryDocumentSnapshot } from "firebase-admin/firestore"; +import type { BaseModel } from "~/models/base-model"; +import type { LocalizedFirestoreDocument } from "~/data/firestore/docs/model-document-mapper.ts"; +import { + isLocalizedField, + type LocalizedField, +} from "~/data/firestore/docs/localized-field.ts"; + +const localizedFieldToFirestore = < + M extends BaseModel, + K extends keyof M, + D extends LocalizedFirestoreDocument, +>( + model: M, + currentLanguage: SupportedLanguages, + localizedFields: K[], + currentDocument: D, +): LocalizedFirestoreDocument => { + const result = { ...model } as unknown as D; + + localizedFields.forEach((field) => { + let localizedValue = { + ...(currentDocument[field] as LocalizedField), + }; + const modelValue = model[field]; + if (!modelValue && currentLanguage === defaultLanguage) { + throw new Error( + `Cannot set default language (${defaultLanguage}) to an empty string for field ${String(field)}`, + ); + } + + if (modelValue) { + if (typeof modelValue !== "string") { + throw new Error(`Field ${String(field)} must be a string in the model`); + } + + if (currentLanguage === defaultLanguage && modelValue.trim() === "") { + throw new Error( + `Cannot set default language (${defaultLanguage}) to an empty string for field ${String(field)}`, + ); + } + + localizedValue[currentLanguage] = modelValue; + } + + result[field] = localizedValue as any; + }); + + return result; +}; + +const localizedFieldFromFirestore = ( + snapshot: QueryDocumentSnapshot, + currentLanguage: SupportedLanguages, + localizedFields: ReadonlyArray, +): M => { + const data = snapshot.data() as LocalizedFirestoreDocument; + const result = { ...data, id: snapshot.id } as M; + + localizedFields.forEach((field) => { + const value = data[field]; + if (isLocalizedField(value)) { + result[field] = value[currentLanguage] as M[K]; + } else { + result[field] = value as M[K]; + } + }); + + return result; +}; + +export { localizedFieldToFirestore, localizedFieldFromFirestore }; diff --git a/src/data/firestore/docs/localized-field.ts b/src/data/firestore/docs/localized-field.ts new file mode 100644 index 00000000..2c97fcbc --- /dev/null +++ b/src/data/firestore/docs/localized-field.ts @@ -0,0 +1,14 @@ +import { defaultLanguage, type supportedLanguages } from "~/constants/i18n"; + +type SupportedLanguage = typeof supportedLanguages[number]; + +type LocalizedField = Partial>; + +const isLocalizedField = (value: unknown): value is LocalizedField => { + return ( + typeof value === "object" && value !== null && defaultLanguage in value + ); +}; + +export type { LocalizedField }; +export { isLocalizedField }; diff --git a/src/data/firestore/docs/model-document-mapper.ts b/src/data/firestore/docs/model-document-mapper.ts new file mode 100644 index 00000000..97f4aae3 --- /dev/null +++ b/src/data/firestore/docs/model-document-mapper.ts @@ -0,0 +1,24 @@ +import { Timestamp } from "firebase-admin/firestore"; +import type { LocalizedField } from "./localized-field"; + +type MapDateToTimestamp = PropType extends Date + ? Timestamp + : PropType; + +type OmitDate = { + [K in keyof T as T[K] extends Date ? never : K]: T[K] +}; + +type FirestoreDocument = Omit, "id"> & { + [PropertyKey in keyof T]: MapDateToTimestamp; +}; + + +type LocalizedFirestoreDocument = Omit< + FirestoreDocument, + K +> & { + [P in keyof T]: P extends K ? LocalizedField : MapDateToTimestamp; +}; + +export type { FirestoreDocument, LocalizedFirestoreDocument }; diff --git a/src/data/firestore/docs/utils.ts b/src/data/firestore/docs/utils.ts new file mode 100644 index 00000000..7ddd7a74 --- /dev/null +++ b/src/data/firestore/docs/utils.ts @@ -0,0 +1,7 @@ +const omit = (obj: T, keys: K[]): Omit => { + const result = { ...obj }; + keys.forEach(key => delete result[key]); + return result; +} + +export default omit; \ No newline at end of file diff --git a/src/data/firestore/user.spec.ts b/src/data/firestore/user.spec.ts index 85217d9a..fb73d11a 100644 --- a/src/data/firestore/user.spec.ts +++ b/src/data/firestore/user.spec.ts @@ -15,7 +15,6 @@ describe("Get docs paginated", () => { { displayName: "Name 1", email: "email@email.it", - organizer: true, }, { displayName: "Name 2", @@ -24,7 +23,9 @@ describe("Get docs paginated", () => { { displayName: "Name 3", email: "email3@email.it", - organizer: true, + customClaims: { + organizer: true, + }, }, { displayName: "Name 4", diff --git a/src/data/firestore/user.ts b/src/data/firestore/user.ts index 19d8be06..5255fc1d 100644 --- a/src/data/firestore/user.ts +++ b/src/data/firestore/user.ts @@ -1,11 +1,11 @@ import type { User } from "~/models/user/user.type"; -import type { FirestoreDocument } from "../model-document-mapper"; import type { FirestoreDataConverter, QueryDocumentSnapshot, } from "firebase-admin/firestore"; import type { PaginationParams } from "~/models/pagination/pagination.type"; import getDocsPaginated from "./common/get-docs-paginated"; +import type { FirestoreDocument } from "~/data/firestore/docs/model-document-mapper.ts"; const collection = "users" as const; diff --git a/src/data/model-document-mapper.ts b/src/data/model-document-mapper.ts deleted file mode 100644 index ec863216..00000000 --- a/src/data/model-document-mapper.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Timestamp } from "firebase-admin/firestore"; - -type MapDateToTimestamp = PropType extends Date - ? Timestamp - : PropType; - -export type FirestoreDocument = { - [PropertyKey in keyof T]: MapDateToTimestamp; -}; diff --git a/src/models/localization/localization.schema.ts b/src/models/localization/localization.schema.ts new file mode 100644 index 00000000..49e0d69f --- /dev/null +++ b/src/models/localization/localization.schema.ts @@ -0,0 +1,8 @@ +import { z } from "astro/zod"; +import { supportedLanguages } from "~/constants/i18n"; + +const localizationParamSchema = z.object({ + language: z.enum(supportedLanguages), +}); + +export { localizationParamSchema }; diff --git a/src/models/localization/localization.type.ts b/src/models/localization/localization.type.ts new file mode 100644 index 00000000..ff808193 --- /dev/null +++ b/src/models/localization/localization.type.ts @@ -0,0 +1,7 @@ +import type { SupportedLanguages } from "~/constants/i18n"; + +type LocalizationParam = { + language?: SupportedLanguages; +}; + +export type { LocalizationParam }; diff --git a/src/models/pagination/pagination.type.ts b/src/models/pagination/pagination.type.ts index 24748a1a..e68ab3a0 100644 --- a/src/models/pagination/pagination.type.ts +++ b/src/models/pagination/pagination.type.ts @@ -1,4 +1,5 @@ import type { GetAllDocumentsParam } from "~/models/get-all/get-all-document.type.ts"; +import type {LocalizationParam} from "~/models/localization/localization.type.ts"; type PaginatedResponse = { data: T[]; @@ -8,7 +9,7 @@ type PaginatedResponse = { totalPages: number; }; -type PaginationParams = GetAllDocumentsParam & { +type PaginationParams = GetAllDocumentsParam & LocalizationParam & { offset: number; limit: number; }; diff --git a/src/models/user/user.type.ts b/src/models/user/user.type.ts index d8c86180..8b659e1b 100644 --- a/src/models/user/user.type.ts +++ b/src/models/user/user.type.ts @@ -3,7 +3,7 @@ import type { BaseModel } from "../base-model"; type User = BaseModel & { displayName: string; email: string; - customClaims: CustomClaims; + customClaims?: CustomClaims; }; type CustomClaims = { diff --git a/src/shared/Dummy/dummy.test.ts b/src/shared/Dummy/dummy.test.ts deleted file mode 100644 index e7fa3f45..00000000 --- a/src/shared/Dummy/dummy.test.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { expect, it } from "vitest"; - -it("should pass", () => { - expect(true).toBe(true); -}); From f1b27407e0eeda569a8e216023978ccb32ee1f40 Mon Sep 17 00:00:00 2001 From: Camillo bucciarelli Date: Tue, 3 Sep 2024 09:14:38 +0200 Subject: [PATCH 2/2] remove import from astro config --- astro.config.mjs | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/astro.config.mjs b/astro.config.mjs index 880642ba..f134d232 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -4,21 +4,15 @@ import tailwind from "@astrojs/tailwind"; import nodejs from "@astrojs/node"; import astroI18next from "astro-i18next"; import icon from "astro-icon"; -import { defaultLanguage, supportedLanguages } from "~/constants/i18n.js"; // https://astro.build/config export default defineConfig({ site: "https://devfest.gdgpescara.it", - integrations: [ - icon({ - include: { - mdi: ["*"], // (Default) Loads entire Material Design Icon set - }, - }), - react(), - tailwind(), - astroI18next(), - ], + integrations: [icon({ + include: { + mdi: ["*"], // (Default) Loads entire Material Design Icon set + }, + }),react(), tailwind(), astroI18next()], output: "hybrid", adapter: nodejs({ mode: "standalone", @@ -27,10 +21,10 @@ export default defineConfig({ domains: ["via.placeholder.com"], }, i18n: { - defaultLocale: defaultLanguage, - locales: supportedLanguages, + defaultLocale: "en", + locales: ["en", "it"], fallback: { - it: defaultLanguage, + it: "en", }, routingStrategy: "prefix-other-locales", },