diff --git a/app/layout.tsx b/app/layout.tsx
index e18935c..992035a 100644
--- a/app/layout.tsx
+++ b/app/layout.tsx
@@ -1,4 +1,8 @@
import '@/app/ui/global.css'
+
+import 'primereact/resources/themes/lara-light-cyan/theme.css';
+import 'primeicons/primeicons.css';
+
import { inter } from '@/app/ui/fonts';
export default function RootLayout({
diff --git a/app/ui/dashboard/nav-links.tsx b/app/ui/dashboard/nav-links.tsx
index 82415b9..ceef053 100644
--- a/app/ui/dashboard/nav-links.tsx
+++ b/app/ui/dashboard/nav-links.tsx
@@ -9,6 +9,8 @@ import Link from 'next/link';
import { usePathname } from 'next/navigation';
import clsx from 'clsx';
+// Map of links to display in the side navigation.
+// Depending on the size of the application, this would be stored in a database.
const links = [
{ name: 'Guests', href: '/dashboard/guests', icon: UserGroupIcon },
{ name: 'Expenses', href: '/dashboard/expenses', icon: BanknotesIcon },
diff --git a/app/ui/guests/affinity-groups-tree.tsx b/app/ui/guests/affinity-groups-tree.tsx
new file mode 100644
index 0000000..95863da
--- /dev/null
+++ b/app/ui/guests/affinity-groups-tree.tsx
@@ -0,0 +1,49 @@
+'use client'
+
+import React, { useState, useEffect, Suspense } from 'react';
+import { Tree } from 'primereact/tree';
+import { PrimeIcons } from 'primereact/api';
+import { debug } from 'console';
+
+export default function AffinityGroupsTree() {
+ const [nodes, setNodes] = useState([]);
+ const parseNode = (record: any, included: any[]) => {
+ if (!record.attributes) {
+ record = included.find((a) => a.id === record.id);
+ }
+
+ const children = (record?.relationships?.children?.data || []).map((child: any) => {
+ return (parseNode(child, included));
+ });
+
+ return ({
+ key: record.id,
+ label: record.attributes.name,
+ icon: record.attributes.icon,
+ children: children,
+ className: "px-4",
+ })
+ }
+
+
+ useEffect(() => {
+ if (nodes.length > 0) {
+ return;
+ }
+ fetch("http://localhost:3001/groups.json")
+ .then((response) => response.json())
+ .then((data) => {
+ setNodes(data.data.map((record: any) => {
+ return (parseNode(record, data.included));
+ }))
+ });
+ });
+
+ return (
+
+
+ setNodes(e.value)} className="w-full md:w-30rem" />
+
+
+ )
+}
\ No newline at end of file
diff --git a/app/ui/guests/table.tsx b/app/ui/guests/table.tsx
index 3d90381..6340b5c 100644
--- a/app/ui/guests/table.tsx
+++ b/app/ui/guests/table.tsx
@@ -42,7 +42,7 @@ export default function guestsTable() {
-
+
{guests.map((guest) => (
diff --git a/package.json b/package.json
index c013c8d..d922491 100644
--- a/package.json
+++ b/package.json
@@ -15,6 +15,8 @@
"next": "15.0.0-canary.56",
"next-auth": "5.0.0-beta.19",
"postcss": "8.4.38",
+ "primeicons": "^7.0.0",
+ "primereact": "^10.8.2",
"react": "19.0.0-rc-f38c22b244-20240704",
"react-dom": "19.0.0-rc-f38c22b244-20240704",
"tailwindcss": "3.4.4",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index d3848c0..3dcdbf8 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -35,6 +35,12 @@ importers:
postcss:
specifier: 8.4.38
version: 8.4.38
+ primeicons:
+ specifier: ^7.0.0
+ version: 7.0.0
+ primereact:
+ specifier: ^10.8.2
+ version: 10.8.2(@types/react@18.3.3)(react-dom@19.0.0-rc-f38c22b244-20240704(react@19.0.0-rc-f38c22b244-20240704))(react@19.0.0-rc-f38c22b244-20240704)
react:
specifier: 19.0.0-rc-f38c22b244-20240704
version: 19.0.0-rc-f38c22b244-20240704
@@ -87,6 +93,10 @@ packages:
nodemailer:
optional: true
+ '@babel/runtime@7.25.0':
+ resolution: {integrity: sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw==}
+ engines: {node: '>=6.9.0'}
+
'@emnapi/runtime@1.2.0':
resolution: {integrity: sha512-bV21/9LQmcQeCPEg3BDFtvwL6cwiTMksYNWQQ4KOxCZikEGalWtenoZ0wCiukJINlGCIi2KXx01g4FoH/LxpzQ==}
@@ -339,6 +349,9 @@ packages:
'@types/react-dom@18.3.0':
resolution: {integrity: sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==}
+ '@types/react-transition-group@4.4.11':
+ resolution: {integrity: sha512-RM05tAniPZ5DZPzzNFP+DmrcOdD0efDUxMy3145oljWSl3x9ZV5vhme98gTxFrj2lhXvmGNnUiuDyJgY9IKkNA==}
+
'@types/react@18.3.3':
resolution: {integrity: sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==}
@@ -516,6 +529,9 @@ packages:
dlv@1.1.3:
resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==}
+ dom-helpers@5.2.1:
+ resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==}
+
eastasianwidth@0.2.0:
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
@@ -648,6 +664,9 @@ packages:
jose@5.4.1:
resolution: {integrity: sha512-U6QajmpV/nhL9SyfAewo000fkiRQ+Yd2H0lBxJJ9apjpOgkOcBQJWOrMo917lxLptdS/n/o/xPzMkXhF46K8hQ==}
+ js-tokens@4.0.0:
+ resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
+
lilconfig@2.1.0:
resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==}
engines: {node: '>=10'}
@@ -659,6 +678,10 @@ packages:
lines-and-columns@1.2.4:
resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
+ loose-envify@1.4.0:
+ resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
+ hasBin: true
+
lru-cache@10.2.2:
resolution: {integrity: sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==}
engines: {node: 14 || >=16.14}
@@ -918,6 +941,23 @@ packages:
pretty-format@3.8.0:
resolution: {integrity: sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew==}
+ primeicons@7.0.0:
+ resolution: {integrity: sha512-jK3Et9UzwzTsd6tzl2RmwrVY/b8raJ3QZLzoDACj+oTJ0oX7L9Hy+XnVwgo4QVKlKpnP/Ur13SXV/pVh4LzaDw==}
+
+ primereact@10.8.2:
+ resolution: {integrity: sha512-bf7vktogGh0PmKT9WLDcJQoQNqqFqcAlP2crUqccnlTu63FNnQV82qEYyaFvE12Qd5qhm3EYmpsHjpf6/+olTQ==}
+ engines: {node: '>=14.0.0'}
+ peerDependencies:
+ '@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
+ react: ^17.0.0 || ^18.0.0 || ^19.0.0
+ react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
+ prop-types@15.8.1:
+ resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
+
queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
@@ -926,6 +966,15 @@ packages:
peerDependencies:
react: 19.0.0-rc-f38c22b244-20240704
+ react-is@16.13.1:
+ resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
+
+ react-transition-group@4.4.5:
+ resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==}
+ peerDependencies:
+ react: '>=16.6.0'
+ react-dom: '>=16.6.0'
+
react@19.0.0-rc-f38c22b244-20240704:
resolution: {integrity: sha512-OP8O6Oc1rdR9IdIKJRKaL1PYd4eGkn6f88VqiygWyyG4P4RmPPix5pp7MatqSt9TnBOcVT+lBMGoVxRgUFeudQ==}
engines: {node: '>=0.10.0'}
@@ -941,6 +990,9 @@ packages:
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
engines: {node: '>=8.10.0'}
+ regenerator-runtime@0.14.1:
+ resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==}
+
resolve@1.22.8:
resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==}
hasBin: true
@@ -1168,6 +1220,10 @@ snapshots:
preact: 10.11.3
preact-render-to-string: 5.2.3(preact@10.11.3)
+ '@babel/runtime@7.25.0':
+ dependencies:
+ regenerator-runtime: 0.14.1
+
'@emnapi/runtime@1.2.0':
dependencies:
tslib: 2.6.3
@@ -1374,6 +1430,10 @@ snapshots:
dependencies:
'@types/react': 18.3.3
+ '@types/react-transition-group@4.4.11':
+ dependencies:
+ '@types/react': 18.3.3
+
'@types/react@18.3.3':
dependencies:
'@types/prop-types': 15.7.12
@@ -1542,6 +1602,11 @@ snapshots:
dlv@1.1.3: {}
+ dom-helpers@5.2.1:
+ dependencies:
+ '@babel/runtime': 7.25.0
+ csstype: 3.1.3
+
eastasianwidth@0.2.0: {}
electron-to-chromium@1.4.789: {}
@@ -1678,12 +1743,18 @@ snapshots:
jose@5.4.1: {}
+ js-tokens@4.0.0: {}
+
lilconfig@2.1.0: {}
lilconfig@3.1.1: {}
lines-and-columns@1.2.4: {}
+ loose-envify@1.4.0:
+ dependencies:
+ js-tokens: 4.0.0
+
lru-cache@10.2.2: {}
make-dir@3.1.0:
@@ -1892,6 +1963,23 @@ snapshots:
pretty-format@3.8.0: {}
+ primeicons@7.0.0: {}
+
+ primereact@10.8.2(@types/react@18.3.3)(react-dom@19.0.0-rc-f38c22b244-20240704(react@19.0.0-rc-f38c22b244-20240704))(react@19.0.0-rc-f38c22b244-20240704):
+ dependencies:
+ '@types/react-transition-group': 4.4.11
+ react: 19.0.0-rc-f38c22b244-20240704
+ react-dom: 19.0.0-rc-f38c22b244-20240704(react@19.0.0-rc-f38c22b244-20240704)
+ react-transition-group: 4.4.5(react-dom@19.0.0-rc-f38c22b244-20240704(react@19.0.0-rc-f38c22b244-20240704))(react@19.0.0-rc-f38c22b244-20240704)
+ optionalDependencies:
+ '@types/react': 18.3.3
+
+ prop-types@15.8.1:
+ dependencies:
+ loose-envify: 1.4.0
+ object-assign: 4.1.1
+ react-is: 16.13.1
+
queue-microtask@1.2.3: {}
react-dom@19.0.0-rc-f38c22b244-20240704(react@19.0.0-rc-f38c22b244-20240704):
@@ -1899,6 +1987,17 @@ snapshots:
react: 19.0.0-rc-f38c22b244-20240704
scheduler: 0.25.0-rc-f38c22b244-20240704
+ react-is@16.13.1: {}
+
+ react-transition-group@4.4.5(react-dom@19.0.0-rc-f38c22b244-20240704(react@19.0.0-rc-f38c22b244-20240704))(react@19.0.0-rc-f38c22b244-20240704):
+ dependencies:
+ '@babel/runtime': 7.25.0
+ dom-helpers: 5.2.1
+ loose-envify: 1.4.0
+ prop-types: 15.8.1
+ react: 19.0.0-rc-f38c22b244-20240704
+ react-dom: 19.0.0-rc-f38c22b244-20240704(react@19.0.0-rc-f38c22b244-20240704)
+
react@19.0.0-rc-f38c22b244-20240704: {}
read-cache@1.0.0:
@@ -1915,6 +2014,8 @@ snapshots:
dependencies:
picomatch: 2.3.1
+ regenerator-runtime@0.14.1: {}
+
resolve@1.22.8:
dependencies:
is-core-module: 2.13.1
|