From 3cda238813e03dacd5b30e021b97c42d8ae8b35b Mon Sep 17 00:00:00 2001 From: Cybervoid Date: Sat, 23 Aug 2025 02:57:58 +0200 Subject: [PATCH 1/8] feat(database): add Document model and update relations in schema - Introduced a new Document model with various fields for document management, including title, catalogue number, and related metadata. - Updated existing models (Image, Barometer, Condition) to establish relationships with the new Document model, enhancing data structure and integrity. --- .../migration.sql | 63 +++++++++++++++++++ prisma/schema.prisma | 33 ++++++++++ 2 files changed, 96 insertions(+) create mode 100644 prisma/migrations/20250823004407_add_document_model/migration.sql diff --git a/prisma/migrations/20250823004407_add_document_model/migration.sql b/prisma/migrations/20250823004407_add_document_model/migration.sql new file mode 100644 index 00000000..7ce7e403 --- /dev/null +++ b/prisma/migrations/20250823004407_add_document_model/migration.sql @@ -0,0 +1,63 @@ +-- CreateTable +CREATE TABLE "Document" ( + "id" TEXT NOT NULL, + "title" TEXT NOT NULL, + "catalogueNumber" TEXT NOT NULL, + "documentType" TEXT NOT NULL, + "subject" TEXT, + "creator" TEXT, + "date" TIMESTAMP(3), + "dateDescription" TEXT, + "placeOfOrigin" TEXT, + "language" TEXT, + "physicalDescription" TEXT, + "annotations" TEXT[], + "provenance" TEXT, + "acquisitionDate" TIMESTAMP(3), + "description" TEXT, + "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "updatedAt" TIMESTAMP(3) NOT NULL, + "conditionId" TEXT, + + CONSTRAINT "Document_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "_DocumentBarometers" ( + "A" TEXT NOT NULL, + "B" TEXT NOT NULL, + + CONSTRAINT "_DocumentBarometers_AB_pkey" PRIMARY KEY ("A","B") +); + +-- CreateTable +CREATE TABLE "_DocumentImages" ( + "A" TEXT NOT NULL, + "B" TEXT NOT NULL, + + CONSTRAINT "_DocumentImages_AB_pkey" PRIMARY KEY ("A","B") +); + +-- CreateIndex +CREATE UNIQUE INDEX "Document_catalogueNumber_key" ON "Document"("catalogueNumber"); + +-- CreateIndex +CREATE INDEX "_DocumentBarometers_B_index" ON "_DocumentBarometers"("B"); + +-- CreateIndex +CREATE INDEX "_DocumentImages_B_index" ON "_DocumentImages"("B"); + +-- AddForeignKey +ALTER TABLE "Document" ADD CONSTRAINT "Document_conditionId_fkey" FOREIGN KEY ("conditionId") REFERENCES "Condition"("id") ON DELETE SET NULL ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "_DocumentBarometers" ADD CONSTRAINT "_DocumentBarometers_A_fkey" FOREIGN KEY ("A") REFERENCES "Barometer"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "_DocumentBarometers" ADD CONSTRAINT "_DocumentBarometers_B_fkey" FOREIGN KEY ("B") REFERENCES "Document"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "_DocumentImages" ADD CONSTRAINT "_DocumentImages_A_fkey" FOREIGN KEY ("A") REFERENCES "Document"("id") ON DELETE CASCADE ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "_DocumentImages" ADD CONSTRAINT "_DocumentImages_B_fkey" FOREIGN KEY ("B") REFERENCES "Image"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index b7ea168d..69310c6d 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -20,6 +20,7 @@ model Image { categories Category[] @relation("CategoryImages") barometers Barometer[] @relation("BarometerImages") manufacturers Manufacturer[] @relation("ManufacturerImages") + documents Document[] @relation("DocumentImages") } model Category { @@ -82,6 +83,7 @@ model Barometer { images Image[] @relation("BarometerImages") reports InaccuracyReport[] materials Material[] @relation("BarometerMaterials") + documents Document[] @relation("DocumentBarometers") } model Material { @@ -143,6 +145,7 @@ model Condition { createdAt DateTime @default(now()) updatedAt DateTime @updatedAt barometers Barometer[] + documents Document[] } model User { @@ -156,6 +159,36 @@ model User { updatedAt DateTime @updatedAt } +model Document { + id String @id @default(uuid()) + title String + catalogueNumber String @unique + documentType String + subject String? + creator String? + /// Date for documents sorting + date DateTime? + /// Date to display on pages, e.g. "c.1870", "mid 19th century" + dateDescription String? + placeOfOrigin String? + language String? + physicalDescription String? + /// List of inscriptions, stamps, etc. + annotations String[] + provenance String? + acquisitionDate DateTime? + description String? + + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + + // Relations + conditionId String? + condition Condition? @relation(fields: [conditionId], references: [id]) + images Image[] @relation("DocumentImages") + relatedBarometers Barometer[] @relation("DocumentBarometers") +} + enum AccessRole { USER OWNER From 1d9146aaac1eea4bdaf4139e054bcef2121b7029 Mon Sep 17 00:00:00 2001 From: Cybervoid Date: Sat, 23 Aug 2025 07:20:19 +0200 Subject: [PATCH 2/8] feat(adding barometer): add purchase date field with validation to barometer form - Introduced a new 'purchasedAt' field in the barometer form to capture purchase dates. - Implemented validation for the purchase date to ensure it is a valid date and not set in the future. - Enhanced form functionality with a date input and clear button for user convenience. - Extended dayjs with UTC plugin for consistent date handling across the application. --- app/admin/add-barometer/page.tsx | 49 +++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/app/admin/add-barometer/page.tsx b/app/admin/add-barometer/page.tsx index a4e4e897..24089667 100644 --- a/app/admin/add-barometer/page.tsx +++ b/app/admin/add-barometer/page.tsx @@ -5,6 +5,7 @@ import { useForm, FormProvider } from 'react-hook-form' import { yupResolver } from '@hookform/resolvers/yup' import * as yup from 'yup' import dayjs from 'dayjs' +import utc from 'dayjs/plugin/utc' import { useMutation, useQueryClient } from '@tanstack/react-query' import { toast } from 'sonner' import { Button } from '@/components/ui/button' @@ -29,11 +30,12 @@ import { useBarometers } from '@/hooks/useBarometers' import { FileUpload } from './file-upload' import { AddManufacturer } from './add-manufacturer' import { Dimensions } from './dimensions' - import { createBarometer } from '@/services/fetch' import { getThumbnailBase64, slug } from '@/utils' import { imageStorage } from '@/constants/globals' +dayjs.extend(utc) + // Form data interface interface BarometerFormData { collectionId: string @@ -46,6 +48,7 @@ interface BarometerFormData { description: string dimensions: Array<{ dim: string; value: string }> images: string[] + purchasedAt: string } // Yup validation schema @@ -81,6 +84,17 @@ const barometerSchema = yup.object().shape({ .of(yup.string().required()) .min(1, 'At least one image is required') .default([]), + purchasedAt: yup + .string() + .test('valid-date', 'Must be a valid date', value => { + if (!value) return true // Allow empty string + return dayjs(value).isValid() + }) + .test('not-future', 'Purchase date cannot be in the future', value => { + if (!value) return true + return dayjs(value).isBefore(dayjs(), 'day') || dayjs(value).isSame(dayjs(), 'day') + }) + .default(''), }) export default function AddCard() { @@ -99,6 +113,7 @@ export default function AddCard() { description: '', dimensions: [], images: [], + purchasedAt: '', }, }) @@ -110,6 +125,7 @@ export default function AddCard() { const barometerWithImages = { ...values, date: dayjs(`${values.date}-01-01`).toISOString(), + purchasedAt: values.purchasedAt ? dayjs.utc(values.purchasedAt).toISOString() : null, images: await Promise.all( (values.images || []).map(async (url, i) => ({ url, @@ -328,6 +344,37 @@ export default function AddCard() { )} /> + ( + + Purchase Date + +
+ + +
+
+ +
+ )} + /> + From 7efb921f3641e5390004f87dae344d0cc50fd7c4 Mon Sep 17 00:00:00 2001 From: Cybervoid Date: Sat, 23 Aug 2025 07:42:14 +0200 Subject: [PATCH 3/8] feat(barometer): add serial number field and enhance form inputs - Introduced a new 'serial' field in the barometer form to capture the serial number. - Updated validation schema to include a maximum length for the serial number. - Enhanced input fields with placeholders for better user guidance. - Modified the purchase date input to include a clear button for improved usability. - Improved layout and descriptions for various form fields to enhance user experience. --- app/admin/add-barometer/page.tsx | 98 +++++++++++++++++++------------- 1 file changed, 60 insertions(+), 38 deletions(-) diff --git a/app/admin/add-barometer/page.tsx b/app/admin/add-barometer/page.tsx index 24089667..03b8d6bd 100644 --- a/app/admin/add-barometer/page.tsx +++ b/app/admin/add-barometer/page.tsx @@ -49,6 +49,7 @@ interface BarometerFormData { dimensions: Array<{ dim: string; value: string }> images: string[] purchasedAt: string + serial: string } // Yup validation schema @@ -95,6 +96,7 @@ const barometerSchema = yup.object().shape({ return dayjs(value).isBefore(dayjs(), 'day') || dayjs(value).isSame(dayjs(), 'day') }) .default(''), + serial: yup.string().max(100, 'Serial number must be less than 100 characters').default(''), }) export default function AddCard() { @@ -106,7 +108,7 @@ export default function AddCard() { collectionId: '', name: '', categoryId: '', - date: '', + date: '1900', dateDescription: '', manufacturerId: '', conditionId: '', @@ -114,6 +116,7 @@ export default function AddCard() { dimensions: [], images: [], purchasedAt: '', + serial: '', }, }) @@ -179,7 +182,7 @@ export default function AddCard() { return (
-

Add new barometer

+

Add new barometer

@@ -191,7 +194,21 @@ export default function AddCard() { Catalogue No. * - + + + + + )} + /> + + ( + + Serial Number + + @@ -205,7 +222,7 @@ export default function AddCard() { Title * - + @@ -221,7 +238,7 @@ export default function AddCard() { { const year = e.target.value.replace(/\D/g, '').slice(0, 4) @@ -241,7 +258,38 @@ export default function AddCard() { Date description * - + + + + + )} + /> + + ( + + Purchase Date + +
+ + +
@@ -337,38 +385,12 @@ export default function AddCard() { Description -