Skip to content

Commit

Permalink
Merge pull request #635 from danactive/add-age
Browse files Browse the repository at this point in the history
Display persons in album w/ Age
  • Loading branch information
danactive authored Nov 18, 2024
2 parents ee43359 + 390e71e commit a1bfe51
Show file tree
Hide file tree
Showing 22 changed files with 1,886 additions and 2,796 deletions.
2 changes: 1 addition & 1 deletion next-env.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
/// <reference types="next/navigation-types/compat/navigation" />

// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.
// see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information.
4,087 changes: 1,375 additions & 2,712 deletions package-lock.json

Large diffs are not rendered by default.

46 changes: 23 additions & 23 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,55 +16,55 @@
"release": "standard-version"
},
"dependencies": {
"@emotion/react": "^11.11.4",
"@emotion/styled": "^11.11.5",
"@emotion/react": "^11.13.3",
"@emotion/styled": "^11.13.0",
"@hello-pangea/dnd": "^16.6.0",
"@mui/joy": "^5.0.0-beta.32",
"boom": "^7.3.0",
"camelcase": "^6.3.0",
"color-thief-react": "^2.1.0",
"glob": "^10.4.2",
"glob": "^10.4.5",
"heic-convert": "^2.1.0",
"mapbox-gl": "^3.4.0",
"mapbox-gl": "^3.8.0",
"mime-types": "^2.1.35",
"next": "^14.2.10",
"next": "^14.2.18",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-image-gallery": "^1.3.0",
"react-map-gl": "^7.1.7",
"stylis": "^4.3.2",
"stylis": "^4.3.4",
"xml2js": "^0.6.2"
},
"devDependencies": {
"@playwright/test": "^1.45.0",
"@testing-library/jest-dom": "^6.4.6",
"@playwright/test": "^1.48.2",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/react": "^15.0.7",
"@types/boom": "^7.3.5",
"@types/geojson": "^7946.0.14",
"@types/heic-convert": "^1.2.3",
"@types/jest": "^29.5.12",
"@types/jest": "^29.5.14",
"@types/mime-types": "^2.1.4",
"@types/node": "^20.14.9",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@types/node": "^20.17.6",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"@types/react-image-gallery": "^1.2.4",
"@types/xml2js": "^0.4.14",
"eslint": "^8.57.0",
"eslint": "^8.57.1",
"eslint-config-airbnb": "^19.0.4",
"eslint-config-next": "^14.2.4",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-jest-dom": "^5.4.0",
"eslint-plugin-jsx-a11y": "^6.9.0",
"eslint-plugin-react": "^7.34.3",
"eslint-config-next": "^14.2.18",
"eslint-plugin-import": "^2.31.0",
"eslint-plugin-jest-dom": "^5.5.0",
"eslint-plugin-jsx-a11y": "^6.10.2",
"eslint-plugin-react": "^7.37.2",
"eslint-plugin-react-hooks": "^4.6.2",
"eslint-plugin-testing-library": "^6.2.2",
"eslint-plugin-testing-library": "^6.4.0",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"next-test-api-route-handler": "^4.0.8",
"snyk": "^1.1292.1",
"next-test-api-route-handler": "^4.0.14",
"snyk": "^1.1294.0",
"standard-version": "^9.5.0",
"ts-jest": "^29.1.5",
"typescript": "^5.5.2"
"ts-jest": "^29.2.5",
"typescript": "^5.6.3"
},
"engines": {
"node": "20",
Expand Down
5 changes: 5 additions & 0 deletions public/galleries/demo/persons.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<persons>
<person first="Mister" last="Gingerbread" dob="2004-01-02" />
<person first="Missus" last="Gingerbread" dob="2004-01-02" />
</persons>
2 changes: 1 addition & 1 deletion public/galleries/demo/sample.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
<photo_loc>Dining Room</photo_loc>
<thumb_caption>Gingerbread</thumb_caption>
<photo_desc>Gingerbread persons</photo_desc>
<search>best^, baked goods, house</search>
<search>best^, baked goods, house, Mister Gingerbread, Missus Gingerbread</search>
</item>
<item id="2">
<filename>2005-07-30-01.jpg</filename>
Expand Down
1 change: 1 addition & 0 deletions src/components/SlippyMap/__tests__/options.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ describe('Options - <SlippyMap />', () => {
caption: 'Mock caption',
description: null,
search: null,
persons: null,
title: 'Mock title',
coordinates: null,
coordinateAccuracy: null,
Expand Down
3 changes: 2 additions & 1 deletion src/components/SlippyMap/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,13 @@ export default function SlippyMap(
if (err) {
return
}
const zoomNotNull = clickZoom === null ? undefined : clickZoom // dep upgrade changed type rules

if (mapRef?.current) {
mapRef.current.flyTo({
// @ts-ignore
center: feature.geometry.coordinates,
zoom: clickZoom,
zoom: zoomNotNull,
})
}
})
Expand Down
7 changes: 6 additions & 1 deletion src/hooks/memory.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@
margin-right: 1rem;
}

.location {
.person {
display: inline;
margin-right: 1rem;
}

.filename {
display: inline;
margin-right: 1rem;
}
4 changes: 3 additions & 1 deletion src/hooks/useMemory.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type ReactImageGallery from 'react-image-gallery'
import Link from '../components/Link'
import type { Item } from '../types/common'
import styles from './memory.module.css'
import applyAge from '../utils/person'

interface Viewed {
(index: number): void;
Expand All @@ -28,7 +29,8 @@ const useMemory = (
const memoryHtml = details ? (
<>
<h3 className={styles.city}>{details.title}</h3>
<h4 className={styles.location}>{details.filename}</h4>
{details.persons && <h4 className={styles.person}>{applyAge(details.persons, details.filename)}</h4>}
<h5 className={styles.filename}>{details.filename}</h5>
{details.reference && <Link href={details.reference[0]}>{decodeURI(details.reference[1]).replaceAll('_', ' ')}</Link>}
</>
) : null
Expand Down
1 change: 1 addition & 0 deletions src/lib/__tests__/search.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ describe('Search hook', () => {
caption: 'Mock caption',
description: null,
search: null,
persons: null,
title: 'Mock title',
coordinates: null,
coordinateAccuracy: null,
Expand Down
36 changes: 14 additions & 22 deletions src/lib/album.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,7 @@
import camelCase from 'camelcase'
import fs from 'node:fs/promises'
import xml2js, { type ParserOptions } from 'xml2js'

import transformJsonSchema, { errorSchema, type ErrorOptionalMessage } from '../models/album'
import transformAlbumSchema, { errorSchema, type ErrorOptionalMessage } from '../models/album'
import type { Album, AlbumMeta } from '../types/common'

const parseOptions: ParserOptions = { explicitArray: false, normalizeTags: true, tagNameProcessors: [(name) => camelCase(name)] }
const parser = new xml2js.Parser(parseOptions)

/**
* Get album XML from local filesystem
* @param {string} gallery name of gallery
* @param {string} album name of album
* @returns {string} album XML
*/
async function getXmlFromFilesystem(gallery: NonNullable<AlbumMeta['gallery']>, album: string) {
const fileBuffer = await fs.readFile(`public/galleries/${gallery}/${album}.xml`)
return parser.parseStringPromise(fileBuffer)
}
import getPersons from './persons'
import { getAlbumFromFilesystem } from './xml'

type Envelope = { body: Album, status: number }
type ErrorOptionalMessageBody = {
Expand Down Expand Up @@ -48,8 +32,16 @@ async function get(
if (!album === null || album === undefined || Array.isArray(album)) {
throw new ReferenceError('Album name is missing')
}
const xml = await getXmlFromFilesystem(gallery, album)
const body = transformJsonSchema(xml)
const jsonAlbum = await getAlbumFromFilesystem(gallery, album)

let relativeDate = null
if (jsonAlbum.album.item) {
const filenames = Array.isArray(jsonAlbum.album.item) ? jsonAlbum.album.item[0].filename : jsonAlbum.album.item.filename
const filename = Array.isArray(filenames) ? filenames[0] : filenames
relativeDate = new Date(filename.substring(0, 10))
}

const body = transformAlbumSchema(jsonAlbum, await getPersons(gallery))

if (returnEnvelope) {
return { body, status: 200 }
Expand All @@ -68,5 +60,5 @@ async function get(
}
}

export { transformJsonSchema }
export { transformAlbumSchema as transformJsonSchema }
export default get
17 changes: 1 addition & 16 deletions src/lib/albums.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
import camelCase from 'camelcase'
import fs from 'node:fs/promises'
import xml2js, { type ParserOptions } from 'xml2js'

import utilsFactory from './utils'
import type {
AlbumMeta,
GalleryAlbum,
XmlGallery,
XmlGalleryAlbum,
} from '../types/common'
import { getGalleryFromFilesystem } from './xml'

type ErrorOptionalMessage = { albums: object[]; error?: { message: string } }
const errorSchema = (message: string): ErrorOptionalMessage => {
Expand All @@ -17,20 +14,8 @@ const errorSchema = (message: string): ErrorOptionalMessage => {
return { ...out, error: { message } }
}

const parseOptions: ParserOptions = { explicitArray: false, normalizeTags: true, tagNameProcessors: [(name) => camelCase(name)] }
const parser = new xml2js.Parser(parseOptions)
const utils = utilsFactory()

/**
* Get Gallery from local filesystem
* @param {string} gallery name of gallery
* @returns {string} album as JSON
*/
async function getGalleryFromFilesystem(gallery: NonNullable<AlbumMeta['gallery']>): Promise<XmlGallery> {
const fileBuffer = await fs.readFile(`public/galleries/${gallery}/gallery.xml`)
return parser.parseStringPromise(fileBuffer)
}

type GalleryAlbums = {
albums: GalleryAlbum[]
}
Expand Down
9 changes: 3 additions & 6 deletions src/lib/filesystems.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,19 +51,16 @@ async function get(
const globPath = path.join(publicPath, destinationPath)

if (!globPath.startsWith(publicPath)) {
return { body: errorSchema('Invalid system path'), status: 404 }
const body = errorSchema('Invalid system path')
return (returnEnvelope ? { body, status: 404 } : body)
}

const files = await glob(decodeURI(`${globPath}/*`))

const webPaths = files.map((file) => transform(file, { destinationPath, globPath })).sort((a, b) => a.name.localeCompare(b.name))

const body = { files: webPaths, destinationPath }
if (returnEnvelope) {
return { body, status: 200 }
}

return body
return (returnEnvelope ? { body, status: 200 } : body)
} catch (e) {
if (returnEnvelope) {
return { body: errorSchema('No files or folders are found'), status: 404 }
Expand Down
48 changes: 48 additions & 0 deletions src/lib/persons.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import transformJsonSchema, { errorSchema, type ErrorOptionalMessage } from '../models/person'
import type { AlbumMeta, Person } from '../types/common'
import { getPersonsFromFilesystem } from './xml'

type Envelope = { body: Person[], status: number }
type ErrorOptionalMessageBody = {
body: ErrorOptionalMessage; status: number;
}
type ReturnAlbumOrErrors = Promise<Envelope | Person[] | ErrorOptionalMessage | ErrorOptionalMessageBody>
async function get<T extends boolean = false>(
gallery: AlbumMeta['gallery'],
returnEnvelope?: T,
): Promise<T extends true ? Envelope : Person[]>
/**
* Get Persons XML from local filesystem
* @param {string} gallery name of gallery
* @param {boolean} returnEnvelope will enable a return value with HTTP status code and body
* @returns {object} person
*/
async function get(
gallery: AlbumMeta['gallery'],
returnEnvelope: boolean,
): ReturnAlbumOrErrors {
try {
if (gallery === null || gallery === undefined) {
throw new ReferenceError('Gallery name is missing')
}
const json = await getPersonsFromFilesystem(gallery)
const body = transformJsonSchema(json)

if (returnEnvelope) {
return { body, status: 200 }
}

return body
} catch (e) {
const message = `No person file was found; gallery=${gallery};`
if (returnEnvelope) {
return { body: errorSchema(message), status: 404 }
}

// eslint-disable-next-line no-console
console.error('ERROR', message, e)
throw e
}
}

export default get
47 changes: 47 additions & 0 deletions src/lib/xml.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import camelCase from 'camelcase'
import fs from 'node:fs/promises'
import xml2js, { type ParserOptions } from 'xml2js'

import type {
AlbumMeta, XmlAlbum, XmlGallery, XmlPersons,
} from '../types/common'

const parseOptions: ParserOptions = { explicitArray: false, normalizeTags: true, tagNameProcessors: [(name) => camelCase(name)] }
const parser = new xml2js.Parser(parseOptions)

/**
* Get Album XML from local filesystem
* @param {string} gallery name of gallery
* @param {string} album name of album
* @returns {string} album XML
*/
async function readAlbum(gallery: NonNullable<AlbumMeta['gallery']>, album: string): Promise<XmlAlbum> {
const fileBuffer = await fs.readFile(`public/galleries/${gallery}/${album}.xml`)
return parser.parseStringPromise(fileBuffer)
}

/**
* Get Gallery XML from local filesystem
* @param {string} gallery name of gallery
* @returns {string} album as JSON
*/
async function readGallery(gallery: NonNullable<AlbumMeta['gallery']>): Promise<XmlGallery> {
const fileBuffer = await fs.readFile(`public/galleries/${gallery}/gallery.xml`)
return parser.parseStringPromise(fileBuffer)
}

/**
* Get Persons XML from local filesystem
* @param {string} gallery name of gallery
* @returns {string} album as JSON
*/
async function readPersons(gallery: NonNullable<AlbumMeta['gallery']>): Promise<XmlPersons> {
const fileBuffer = await fs.readFile(`public/galleries/${gallery}/persons.xml`)
return parser.parseStringPromise(fileBuffer)
}

export {
readAlbum as getAlbumFromFilesystem,
readGallery as getGalleryFromFilesystem,
readPersons as getPersonsFromFilesystem,
}
Loading

0 comments on commit a1bfe51

Please sign in to comment.