first commit

This commit is contained in:
nico 2025-08-27 15:57:20 +02:00
commit eb287dccc1
Signed by: Nicolas
SSH key fingerprint: SHA256:ELi8eDeNLl5PTn64G+o2Kx5+XVDfHF5um2tZigfwWkM
6 changed files with 6208 additions and 0 deletions

3
.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
.DS_Store
node_modules
dist

5955
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

32
package.json Normal file
View file

@ -0,0 +1,32 @@
{
"name": "create-json-from-collection",
"description": "Please enter a description for your extension",
"icon": "extension",
"version": "1.0.0",
"keywords": [
"directus",
"directus-extension",
"directus-extension-hook"
],
"type": "module",
"files": [
"dist"
],
"directus:extension": {
"type": "hook",
"path": "dist/index.js",
"source": "src/index.ts",
"host": "^10.10.0"
},
"scripts": {
"build": "directus-extension build",
"dev": "directus-extension build -w --no-minify",
"link": "directus-extension link",
"validate": "directus-extension validate"
},
"devDependencies": {
"@directus/extensions-sdk": "16.0.0",
"@types/node": "^24.3.0",
"typescript": "^5.9.2"
}
}

179
src/index.ts Normal file
View file

@ -0,0 +1,179 @@
import { defineHook } from "@directus/extensions-sdk"
import { writeFile } from "fs/promises"
import { join } from "path"
import { formatDate } from "./utils"
export default defineHook(({ action }, { env }) => {
const mapsGraphQLQuery = `
query getMaps {
maps {
id
property_name
description
date_created
photos {
photo {
id
}
}
property_code_type
property_type
geoFeatures
property_rooms
property_surface
property_sell
property_fees
property_price
property_dpe_conso
property_dpe_ges
property_dpe_date
property_depenses_min
property_depenses_max
property_depenses_est
property_dpe_date_price
}
}
`
const handleMapsEvent = async () => {
const response = await fetch(`${env.PUBLIC_URL}/graphql`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${env.API_TOKEN}`,
},
body: JSON.stringify({ query: mapsGraphQLQuery }),
})
const json = await response.json()
const allMaps = json.data?.maps ?? []
const transformMapData = (maps: any[]): {} => {
const annonces: any[] = maps.map((map) => ({
annonce: {
// ANNONCE
reference: map.id,
titre: map.property_name,
texte: map?.description ?? "Pas encore de description.",
date_saisie: formatDate(map.date_created),
photos:
map?.photos?.map((img: any) => ({
photo: `${env.PUBLIC_URL}/assets/${img.photo.id}`,
})) ?? null,
// BIEN
code_type: map.property_code_type ?? undefined,
libelle_type: map.property_type ?? undefined,
code_postal: map.geoFeatures.properties.postcode,
ville: map.geoFeatures.properties.city,
nb_pieces_logement: map.property_rooms,
surface: map.property_surface ?? undefined,
adresse: map.geoFeatures.properties.name ?? undefined,
// PRESTATION
type: map.property_sell,
frais_agence: map.property_fees,
// si vente
prix: map.property_sell !== "L" ? map.property_price : undefined,
// si location
loyer_mensuel:
map.property_sell === "L" ? map.property_price : undefined,
// DPE
dpe_valeur_conso: map.property_dpe_conso,
dpe_valeur_ges: map.property_dpe_ges,
dpe_date_realisation: formatDate(map.property_dpe_date),
montant_depenses_energies_min: map.property_depenses_min,
montant_depenses_energies_max: map.property_depenses_max,
montant_depenses_energies_estime: map.property_depenses_est,
date_indice_prix_energies: map.property_dpe_date_price,
// Array handling with optional chaining
categories:
map?.categories?.map((cat: any) => cat?.name) ?? undefined,
// Date handling
updatedAt: map?.date_updated,
// Complex nested objects
settings: {
zoom: map?.settings?.zoom ?? 10,
theme: map?.settings?.theme ?? "default",
markers: map?.settings?.markers?.enabled ?? false,
},
// Conditional assignment using optional chaining
...(map?.location && {
latitude: map.location?.lat,
longitude: map.location?.lng,
}),
// Keep some original structure if it exists
...(map?.metadata && { originalMetadata: map.metadata }),
},
}))
return { client: [...annonces] }
}
// apply key remapping
const transformedMaps = Array.isArray(allMaps)
? transformMapData(allMaps)
: []
const jsonData = JSON.stringify(transformedMaps, null, 2)
// write to existing file
const filePath = join(env.OUTPUT_DIR, env.OUTPUT_FILENAME)
await writeFile(filePath, jsonData, "utf8")
}
// // Updates the maps JSON file by fetching all maps and writing to file
// const updateMapsFile = async (): Promise<void> => {
// try {
// const schema = await getSchema()
// const itemsService = new ItemsService(COLLECTION_NAME, {
// schema,
// accountability: null, // Use null for full access in hooks
// })
// // get all items in collection
// const allMaps = await itemsService.readByQuery({})
// console.log(allMaps)
// // Transform the data before serializing
// const transformedMaps = Array.isArray(allMaps)
// ? transformMapData(allMaps)
// : []
// // format items to JSON
// const jsonData = JSON.stringify(transformedMaps, null, 2)
// console.log(
// `Updating maps file with ${
// Array.isArray(allMaps) ? allMaps.length : 0
// } items`
// )
// const filePath = join(OUTPUT_DIR, OUTPUT_FILENAME)
// // write JSON to file (already exists)
// await writeFile(filePath, jsonData, "utf8")
// console.log(`Maps file successfully updated at: ${filePath}`)
// } catch (error) {
// console.error("Error updating maps file:", error)
// throw error
// }
// }
// Register hook for all CRUD operations on maps
const mapsActions = [
`${env.COLLECTION}.items.create`,
`${env.COLLECTION}.items.update`,
`${env.COLLECTION}.items.delete`,
]
mapsActions.forEach((actionName) => {
action(actionName, handleMapsEvent)
})
})

11
src/utils.ts Normal file
View file

@ -0,0 +1,11 @@
export const formatDate = (
date: string,
options?: Intl.DateTimeFormatOptions
) => {
const defaultOptions: Intl.DateTimeFormatOptions = {
year: "numeric",
month: "numeric",
day: "numeric",
}
return new Date(date).toLocaleDateString("fr", options ?? defaultOptions)
}

28
tsconfig.json Normal file
View file

@ -0,0 +1,28 @@
{
"compilerOptions": {
"target": "ES2019",
"lib": ["ES2019", "DOM"],
"moduleResolution": "node",
"strict": true,
"noFallthroughCasesInSwitch": true,
"esModuleInterop": true,
"noImplicitAny": true,
"noImplicitThis": true,
"noImplicitReturns": true,
"noUnusedLocals": true,
"noUncheckedIndexedAccess": true,
"noUnusedParameters": true,
"alwaysStrict": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"strictBindCallApply": true,
"strictPropertyInitialization": true,
"resolveJsonModule": false,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"allowSyntheticDefaultImports": true,
"isolatedModules": true,
"rootDir": "./src"
},
"include": ["./src/**/*.ts"]
}