diff --git a/app/(pages)/brands/page.tsx b/app/(pages)/brands/page.tsx index ccdfc031..ddc96c2a 100644 --- a/app/(pages)/brands/page.tsx +++ b/app/(pages)/brands/page.tsx @@ -155,12 +155,12 @@ export default async function Brands() { className="group flex items-center justify-between py-0.5 px-2 rounded-lg border bg-card hover:bg-accent hover:border-primary/50 transition-all duration-200 no-underline" >
- {country.flag || '🏭'} + {country.flag || '🏭'} {country.name}
- + {country._count.manufacturers} diff --git a/app/(pages)/collection/items/[slug]/components/edit-fields/brand-edit.tsx b/app/(pages)/collection/items/[slug]/components/edit-fields/brand-edit.tsx index fa4e7c72..da84fad1 100644 --- a/app/(pages)/collection/items/[slug]/components/edit-fields/brand-edit.tsx +++ b/app/(pages)/collection/items/[slug]/components/edit-fields/brand-edit.tsx @@ -6,7 +6,7 @@ import { useCallback, useEffect, useMemo, useState, useTransition } from 'react' import { FormProvider, useForm } from 'react-hook-form' import { toast } from 'sonner' import { z } from 'zod' -import { ClearButton, RequiredFieldMark } from '@/components/elements' +import { ClearButton, EditButton, RequiredFieldMark } from '@/components/elements' import { Button, Command, @@ -29,7 +29,6 @@ import { updateBarometer } from '@/server/barometers/actions' import type { BarometerDTO } from '@/server/barometers/queries' import type { AllBrandsDTO } from '@/server/brands/queries' import { cn } from '@/utils' -import { EditButton } from './edit-button' interface Props { barometer: NonNullable @@ -97,7 +96,7 @@ function BrandEdit({ brands, barometer }: Props) { return ( - +
diff --git a/app/(pages)/collection/items/[slug]/components/edit-fields/category-edit.tsx b/app/(pages)/collection/items/[slug]/components/edit-fields/category-edit.tsx index 9101b27f..ecae5456 100644 --- a/app/(pages)/collection/items/[slug]/components/edit-fields/category-edit.tsx +++ b/app/(pages)/collection/items/[slug]/components/edit-fields/category-edit.tsx @@ -6,6 +6,7 @@ import { useCallback, useEffect, useState, useTransition } from 'react' import { FormProvider, useForm } from 'react-hook-form' import { toast } from 'sonner' import { z } from 'zod' +import { EditButton } from '@/components/elements/EditButton' import { Button, Dialog, @@ -26,7 +27,6 @@ import { import { updateBarometer } from '@/server/barometers/actions' import type { BarometerDTO } from '@/server/barometers/queries' import type { CategoriesDTO } from '@/server/categories/queries' -import { EditButton } from './edit-button' interface Props { barometer: NonNullable @@ -80,7 +80,7 @@ export function CategoryEdit({ barometer, categories }: Props) { return ( - + diff --git a/app/(pages)/collection/items/[slug]/components/edit-fields/condition-edit.tsx b/app/(pages)/collection/items/[slug]/components/edit-fields/condition-edit.tsx index cc897277..5011ad13 100644 --- a/app/(pages)/collection/items/[slug]/components/edit-fields/condition-edit.tsx +++ b/app/(pages)/collection/items/[slug]/components/edit-fields/condition-edit.tsx @@ -5,6 +5,7 @@ import { useCallback, useEffect, useState, useTransition } from 'react' import { useForm } from 'react-hook-form' import { toast } from 'sonner' import { z } from 'zod' +import { EditButton } from '@/components/elements/EditButton' import { Button, Dialog, @@ -27,7 +28,6 @@ import { import { updateBarometer } from '@/server/barometers/actions' import type { BarometerDTO } from '@/server/barometers/queries' import type { ConditionsDTO } from '@/server/conditions/queries' -import { EditButton } from './edit-button' interface ConditionEditProps { barometer: NonNullable @@ -82,7 +82,7 @@ export function ConditionEdit({ barometer, conditions }: ConditionEditProps) { return ( - + diff --git a/app/(pages)/collection/items/[slug]/components/edit-fields/date-edit.tsx b/app/(pages)/collection/items/[slug]/components/edit-fields/date-edit.tsx index c96802b7..0768c8d4 100644 --- a/app/(pages)/collection/items/[slug]/components/edit-fields/date-edit.tsx +++ b/app/(pages)/collection/items/[slug]/components/edit-fields/date-edit.tsx @@ -2,11 +2,11 @@ import { zodResolver } from '@hookform/resolvers/zod' import dayjs from 'dayjs' -import { Edit } from 'lucide-react' import { type ComponentProps, useEffect, useState, useTransition } from 'react' import { FormProvider, useForm } from 'react-hook-form' import { toast } from 'sonner' import { z } from 'zod' +import { EditButton } from '@/components/elements' import { Button, Dialog, @@ -14,7 +14,6 @@ import { DialogDescription, DialogHeader, DialogTitle, - DialogTrigger, FormControl, FormField, FormItem, @@ -24,7 +23,6 @@ import { } from '@/components/ui' import { updateBarometer } from '@/server/barometers/actions' import type { BarometerDTO } from '@/server/barometers/queries' -import { cn } from '@/utils' interface DateEditProps extends ComponentProps<'button'> { size?: string | number | undefined @@ -47,7 +45,7 @@ const validationSchema = z.object({ type DateForm = z.output -export function DateEdit({ size = 18, barometer, className, ...props }: DateEditProps) { +export function DateEdit({ barometer }: DateEditProps) { const [open, setOpen] = useState(false) const [isPending, startTransition] = useTransition() const form = useForm({ @@ -82,16 +80,7 @@ export function DateEdit({ size = 18, barometer, className, ...props }: DateEdit return ( - - - + diff --git a/app/(pages)/collection/items/[slug]/components/edit-fields/dimensions-edit.tsx b/app/(pages)/collection/items/[slug]/components/edit-fields/dimensions-edit.tsx index 7d9249f7..a2f83312 100644 --- a/app/(pages)/collection/items/[slug]/components/edit-fields/dimensions-edit.tsx +++ b/app/(pages)/collection/items/[slug]/components/edit-fields/dimensions-edit.tsx @@ -2,11 +2,12 @@ import { zodResolver } from '@hookform/resolvers/zod' import { isEqual } from 'lodash' -import { Edit, Plus, Trash2 } from 'lucide-react' +import { Plus, Trash2 } from 'lucide-react' import { type ComponentProps, useCallback, useEffect, useState, useTransition } from 'react' import { useFieldArray, useForm } from 'react-hook-form' import { toast } from 'sonner' import { z } from 'zod' +import { EditButton } from '@/components/elements' import { Button, Dialog, @@ -14,7 +15,6 @@ import { DialogDescription, DialogHeader, DialogTitle, - DialogTrigger, FormControl, FormField, FormItem, @@ -25,7 +25,6 @@ import { import { updateBarometer } from '@/server/barometers/actions' import type { BarometerDTO } from '@/server/barometers/queries' import type { Dimensions } from '@/types' -import { cn } from '@/utils' interface DimensionEditProps extends ComponentProps<'button'> { barometer: NonNullable @@ -46,7 +45,7 @@ const validationSchema = z.object({ type DimensionsForm = z.output -export function DimensionEdit({ barometer, className, ...props }: DimensionEditProps) { +export function DimensionEdit({ barometer }: DimensionEditProps) { const [open, setOpen] = useState(false) const [isPending, startTransition] = useTransition() const form = useForm({ @@ -99,16 +98,7 @@ export function DimensionEdit({ barometer, className, ...props }: DimensionEditP return ( - - - + diff --git a/app/(pages)/collection/items/[slug]/components/edit-fields/estimated-price-edit.tsx b/app/(pages)/collection/items/[slug]/components/edit-fields/estimated-price-edit.tsx index 22b9c879..d70fd818 100644 --- a/app/(pages)/collection/items/[slug]/components/edit-fields/estimated-price-edit.tsx +++ b/app/(pages)/collection/items/[slug]/components/edit-fields/estimated-price-edit.tsx @@ -1,11 +1,11 @@ 'use client' import { zodResolver } from '@hookform/resolvers/zod' -import { Edit } from 'lucide-react' import { type ComponentProps, useEffect, useState, useTransition } from 'react' import { useForm } from 'react-hook-form' import { toast } from 'sonner' import { z } from 'zod' +import { EditButton } from '@/components/elements' import { Button, Dialog, @@ -13,7 +13,6 @@ import { DialogDescription, DialogHeader, DialogTitle, - DialogTrigger, FormControl, FormField, FormItem, @@ -24,7 +23,6 @@ import { } from '@/components/ui' import { updateBarometer } from '@/server/barometers/actions' import type { BarometerDTO } from '@/server/barometers/queries' -import { cn } from '@/utils' interface EstimatedPriceEditProps extends ComponentProps<'button'> { size?: string | number | undefined @@ -40,12 +38,7 @@ const validationSchema = z.object({ type EstimatedPriceForm = z.output -export function EstimatedPriceEdit({ - size = 18, - barometer, - className, - ...props -}: EstimatedPriceEditProps) { +export function EstimatedPriceEdit({ barometer }: EstimatedPriceEditProps) { const [open, setOpen] = useState(false) const [isPending, startTransition] = useTransition() const form = useForm({ @@ -84,16 +77,7 @@ export function EstimatedPriceEdit({ return ( - - - + diff --git a/app/(pages)/collection/items/[slug]/components/edit-fields/images-edit.tsx b/app/(pages)/collection/items/[slug]/components/edit-fields/images-edit.tsx index b8f56d28..6031da0e 100644 --- a/app/(pages)/collection/items/[slug]/components/edit-fields/images-edit.tsx +++ b/app/(pages)/collection/items/[slug]/components/edit-fields/images-edit.tsx @@ -1,12 +1,11 @@ 'use client' import { zodResolver } from '@hookform/resolvers/zod' -import { Edit } from 'lucide-react' import { type ComponentProps, useEffect, useMemo, useState, useTransition } from 'react' import { useForm } from 'react-hook-form' import { toast } from 'sonner' import { z } from 'zod' -import { ImageUpload } from '@/components/elements' +import { EditButton, ImageUpload } from '@/components/elements' import { Button, Dialog, @@ -14,7 +13,6 @@ import { DialogDescription, DialogHeader, DialogTitle, - DialogTrigger, FormProvider, LoadingOverlay, } from '@/components/ui' @@ -55,7 +53,7 @@ const TransformSchema = ImagesEditSchema.transform( }, ) -export function ImagesEdit({ barometer, size, className, ...props }: ImagesEditProps) { +export function ImagesEdit({ barometer }: ImagesEditProps) { const savedImages = useMemo( () => barometer.images.map(img => ({ @@ -112,16 +110,7 @@ export function ImagesEdit({ barometer, size, className, ...props }: ImagesEditP return ( - - - + diff --git a/app/(pages)/collection/items/[slug]/components/edit-fields/materials-edit.tsx b/app/(pages)/collection/items/[slug]/components/edit-fields/materials-edit.tsx index 4288d88c..d2e43845 100644 --- a/app/(pages)/collection/items/[slug]/components/edit-fields/materials-edit.tsx +++ b/app/(pages)/collection/items/[slug]/components/edit-fields/materials-edit.tsx @@ -2,11 +2,12 @@ import { zodResolver } from '@hookform/resolvers/zod' import { isEqual } from 'lodash' -import { Check, Edit, X } from 'lucide-react' +import { Check, X } from 'lucide-react' import { type ComponentProps, useEffect, useState, useTransition } from 'react' import { useForm } from 'react-hook-form' import { toast } from 'sonner' import { z } from 'zod' +import { EditButton } from '@/components/elements' import { Badge, Button, @@ -21,7 +22,6 @@ import { DialogDescription, DialogHeader, DialogTitle, - DialogTrigger, FormControl, FormField, FormItem, @@ -35,7 +35,6 @@ import { import { updateBarometer } from '@/server/barometers/actions' import type { BarometerDTO } from '@/server/barometers/queries' import type { MaterialsDTO } from '@/server/materials/queries' -import { cn } from '@/utils' interface MaterialsEditProps extends ComponentProps<'button'> { barometer: NonNullable @@ -48,7 +47,7 @@ const validationSchema = z.object({ type MaterialsForm = z.output -export function MaterialsEdit({ barometer, materials, className, ...props }: MaterialsEditProps) { +export function MaterialsEdit({ barometer, materials }: MaterialsEditProps) { const [open, setOpen] = useState(false) const [isPending, startTransition] = useTransition() @@ -92,16 +91,7 @@ export function MaterialsEdit({ barometer, materials, className, ...props }: Mat return ( - - - + diff --git a/app/(pages)/collection/items/[slug]/components/edit-fields/movements-edit.tsx b/app/(pages)/collection/items/[slug]/components/edit-fields/movements-edit.tsx index 0ecea257..67948d72 100644 --- a/app/(pages)/collection/items/[slug]/components/edit-fields/movements-edit.tsx +++ b/app/(pages)/collection/items/[slug]/components/edit-fields/movements-edit.tsx @@ -1,11 +1,11 @@ 'use client' import { zodResolver } from '@hookform/resolvers/zod' -import { Edit } from 'lucide-react' import { type ComponentProps, useEffect, useState, useTransition } from 'react' import { useForm } from 'react-hook-form' import { toast } from 'sonner' import { z } from 'zod' +import { EditButton } from '@/components/elements' import { Button, Dialog, @@ -13,7 +13,6 @@ import { DialogDescription, DialogHeader, DialogTitle, - DialogTrigger, FormControl, FormField, FormItem, @@ -29,7 +28,6 @@ import { import { updateBarometer } from '@/server/barometers/actions' import type { BarometerDTO } from '@/server/barometers/queries' import type { MovementsDTO } from '@/server/movements/queries' -import { cn } from '@/utils' interface SubcategoryEditProps extends ComponentProps<'button'> { size?: string | number | undefined @@ -45,13 +43,7 @@ const validationSchema = z.object({ type SubcategoryForm = z.output -export function MovementsEdit({ - size = 18, - barometer, - movements, - className, - ...props -}: SubcategoryEditProps) { +export function MovementsEdit({ barometer, movements }: SubcategoryEditProps) { const [open, setOpen] = useState(false) const [isPending, startTransition] = useTransition() @@ -93,16 +85,7 @@ export function MovementsEdit({ return ( - - - + diff --git a/app/(pages)/collection/items/[slug]/components/edit-fields/purchased-at-edit.tsx b/app/(pages)/collection/items/[slug]/components/edit-fields/purchased-at-edit.tsx index 10df1475..96a13cc9 100644 --- a/app/(pages)/collection/items/[slug]/components/edit-fields/purchased-at-edit.tsx +++ b/app/(pages)/collection/items/[slug]/components/edit-fields/purchased-at-edit.tsx @@ -3,11 +3,11 @@ import { zodResolver } from '@hookform/resolvers/zod' import dayjs from 'dayjs' import utc from 'dayjs/plugin/utc' -import { Edit } from 'lucide-react' import { type ComponentProps, useEffect, useState, useTransition } from 'react' import { useForm } from 'react-hook-form' import { toast } from 'sonner' import { z } from 'zod' +import { EditButton } from '@/components/elements' import { Button, Dialog, @@ -15,7 +15,6 @@ import { DialogDescription, DialogHeader, DialogTitle, - DialogTrigger, FormControl, FormField, FormItem, @@ -26,7 +25,6 @@ import { } from '@/components/ui' import { updateBarometer } from '@/server/barometers/actions' import type { BarometerDTO } from '@/server/barometers/queries' -import { cn } from '@/utils' dayjs.extend(utc) interface PurchasedAtEditProps extends ComponentProps<'button'> { @@ -48,12 +46,7 @@ const validationSchema = z.object({ type PurchasedAtForm = z.output -export function PurchasedAtEdit({ - size = 18, - barometer, - className, - ...props -}: PurchasedAtEditProps) { +export function PurchasedAtEdit({ barometer }: PurchasedAtEditProps) { const [open, setOpen] = useState(false) const [isPending, startTransition] = useTransition() const form = useForm({ @@ -101,16 +94,7 @@ export function PurchasedAtEdit({ return ( - - - + diff --git a/app/(pages)/collection/items/[slug]/components/edit-fields/textarea-edit.tsx b/app/(pages)/collection/items/[slug]/components/edit-fields/textarea-edit.tsx index d8ba26ed..a2fc1114 100644 --- a/app/(pages)/collection/items/[slug]/components/edit-fields/textarea-edit.tsx +++ b/app/(pages)/collection/items/[slug]/components/edit-fields/textarea-edit.tsx @@ -2,11 +2,11 @@ import { zodResolver } from '@hookform/resolvers/zod' import { isEqual } from 'lodash' -import { Edit } from 'lucide-react' import { type ComponentProps, useEffect, useState, useTransition } from 'react' import { useForm } from 'react-hook-form' import { toast } from 'sonner' import { z } from 'zod' +import { EditButton } from '@/components/elements' import { Button, Dialog, @@ -14,7 +14,6 @@ import { DialogDescription, DialogHeader, DialogTitle, - DialogTrigger, FormControl, FormField, FormItem, @@ -25,7 +24,6 @@ import { } from '@/components/ui' import { updateBarometer } from '@/server/barometers/actions' import type { BarometerDTO } from '@/server/barometers/queries' -import { cn } from '@/utils' interface TextAreaEditProps extends ComponentProps<'button'> { size?: string | number | undefined @@ -40,14 +38,7 @@ const validationSchema = z.object({ type TextAreaForm = z.output -export function TextAreaEdit({ - size = 18, - barometer, - property, - label, - className, - ...props -}: TextAreaEditProps) { +export function TextAreaEdit({ barometer, property, label }: TextAreaEditProps) { const [open, setOpen] = useState(false) const [isPending, startTransition] = useTransition() @@ -88,16 +79,7 @@ export function TextAreaEdit({ return ( - - - + diff --git a/app/(pages)/collection/items/[slug]/components/edit-fields/textfield-edit.tsx b/app/(pages)/collection/items/[slug]/components/edit-fields/textfield-edit.tsx index cdafba82..34ebc5c4 100644 --- a/app/(pages)/collection/items/[slug]/components/edit-fields/textfield-edit.tsx +++ b/app/(pages)/collection/items/[slug]/components/edit-fields/textfield-edit.tsx @@ -1,12 +1,12 @@ 'use client' import { zodResolver } from '@hookform/resolvers/zod' -import { Edit } from 'lucide-react' import { useRouter } from 'next/navigation' import { useEffect, useState, useTransition } from 'react' import { useForm } from 'react-hook-form' import { toast } from 'sonner' import { z } from 'zod' +import { EditButton } from '@/components/elements' import { Button, Dialog, @@ -14,7 +14,6 @@ import { DialogDescription, DialogHeader, DialogTitle, - DialogTrigger, FormControl, FormField, FormItem, @@ -25,7 +24,6 @@ import { import { Route } from '@/constants/routes' import { updateBarometer } from '@/server/barometers/actions' import type { BarometerDTO } from '@/server/barometers/queries' -import { cn } from '@/utils' interface TextFieldEditProps { size?: number @@ -40,7 +38,7 @@ const textFieldSchema = z.object({ type FormData = z.infer -export function TextFieldEdit({ size = 18, barometer, property, className }: TextFieldEditProps) { +export function TextFieldEdit({ barometer, property }: TextFieldEditProps) { const router = useRouter() const [open, setOpen] = useState(false) const [isPending, startTransition] = useTransition() @@ -83,17 +81,7 @@ export function TextFieldEdit({ size = 18, barometer, property, className }: Tex return ( - - - - + diff --git a/app/(pages)/documents/DocumentEdit.tsx b/app/(pages)/documents/DocumentEdit.tsx new file mode 100644 index 00000000..61a96beb --- /dev/null +++ b/app/(pages)/documents/DocumentEdit.tsx @@ -0,0 +1,470 @@ +'use client' + +import { zodResolver } from '@hookform/resolvers/zod' +import { Trash2 } from 'lucide-react' +import { useRouter } from 'next/navigation' +import { useCallback, useEffect, useMemo, useState } from 'react' +import { useForm } from 'react-hook-form' +import { toast } from 'sonner' +import { EditButton, ImageUpload, MultiSelect, RequiredFieldMark } from '@/components/elements' +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, + AlertDialogTrigger, + Button, + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, + FormControl, + FormField, + FormItem, + FormLabel, + FormMessage, + FormProvider, + Input, + LoadingOverlay, + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, + Textarea, +} from '@/components/ui' +import type { AllBarometersDTO } from '@/server/barometers/queries' +import type { ConditionsDTO } from '@/server/conditions/queries' +import { deleteDocument, updateDocument } from '@/server/documents/actions' +import type { AllDocumentsDTO } from '@/server/documents/queries' +import { deleteFiles } from '@/server/files/actions' +import type { MediaFile } from '@/types' +import { cn } from '@/utils' +import { + type DocumentEditForm, + DocumentEditSchema, + DocumentEditTransformSchema, +} from './document-edit-schema' + +type DocumentType = AllDocumentsDTO[number] + +interface Props { + document: DocumentType + conditions: ConditionsDTO + allBarometers: AllBarometersDTO +} + +export function DocumentEdit({ document, conditions, allBarometers }: Props) { + const router = useRouter() + const [loading, setLoading] = useState(false) + const [openDialog, setOpenDialog] = useState(false) + const [openDeleteDialog, setOpenDeleteDialog] = useState(false) + + const docImages = useMemo( + () => (document.images ?? []).map(img => ({ name: img.name ?? '', url: img.url }) as MediaFile), + [document.images], + ) + + const form = useForm({ + resolver: zodResolver(DocumentEditSchema), + mode: 'onSubmit', + reValidateMode: 'onChange', + }) + + const onUpdate = useCallback( + async (values: DocumentEditForm) => { + setLoading(true) + try { + if (!form.formState.isDirty) { + toast.info('No changes to save') + setOpenDialog(false) + return + } + + const deletedImages = docImages.filter( + img => !values.images.some(({ url }) => img.url === url), + ) + + const result = await updateDocument(await DocumentEditTransformSchema.parseAsync(values)) + if (!result.success) throw new Error(result.error) + toast.success(`Document "${result.data.title}" was updated`) + + setTimeout(() => { + setLoading(false) + setOpenDialog(false) + router.refresh() + if (deletedImages.length > 0) deleteFiles(deletedImages) + }, 100) + } catch (error) { + toast.error(error instanceof Error ? error.message : 'Error updating document') + setLoading(false) + } + }, + [form.formState.isDirty, docImages, router], + ) + + const onDelete = useCallback(async () => { + try { + setLoading(true) + const result = await deleteDocument(document.id) + if (!result.success) throw new Error(result.error) + toast.success(`Document "${document.title}" was deleted`) + setOpenDeleteDialog(false) + setOpenDialog(false) + router.refresh() + } catch (error) { + toast.error(error instanceof Error ? error.message : 'Error deleting document') + } finally { + setLoading(false) + } + }, [document, router]) + + useEffect(() => { + if (!openDialog) return + form.reset({ + id: document.id, + title: document.title, + catalogueNumber: document.catalogueNumber, + documentType: document.documentType, + subject: document.subject ?? '', + creator: document.creator ?? '', + date: document.date ? new Date(document.date).toISOString().split('T')[0] : '', + dateDescription: document.dateDescription ?? '', + placeOfOrigin: document.placeOfOrigin ?? '', + language: document.language ?? '', + physicalDescription: document.physicalDescription ?? '', + annotations: document.annotations?.join('\n') ?? '', + provenance: document.provenance ?? '', + acquisitionDate: document.acquisitionDate + ? new Date(document.acquisitionDate).toISOString().split('T')[0] + : '', + description: document.description ?? '', + conditionId: document.conditionId ?? '', + images: document.images.map(({ url, name }) => ({ url, name: name ?? '' })), + relatedBarometers: [], + }) + }, [openDialog, document, form]) + + return ( + // biome-ignore lint/a11y/noStaticElementInteractions: wrapper to stop event propagation to table row +
e.stopPropagation()}> + + + + {loading && } + +
+ Edit Document + + + + + + + Delete Document + + Are you sure you want to delete "{document.title}"? This action cannot be + undone. + + + + Cancel + + Delete + + + + +
+ Update document details. +
+ + + + ( + + + Title + + + + + + + )} + /> + +
+ ( + + + Catalogue Number + + + + + + + )} + /> + + ( + + + Document Type + + + + + + + )} + /> +
+ +
+ ( + + Creator + + + + + + )} + /> + + ( + + Subject + + + + + + )} + /> +
+ +
+ ( + + Date + + + + + + )} + /> + + ( + + Date Description + + + + + + )} + /> +
+ +
+ ( + + Place of Origin + + + + + + )} + /> + + ( + + Language + + + + + + )} + /> +
+ + ( + + Description + +