Merge remote-tracking branch 'origin/main' into cloudflare
This commit is contained in:
commit
0c415ee24b
@ -113,6 +113,7 @@
|
|||||||
"next-safe-action": "^7.10.4",
|
"next-safe-action": "^7.10.4",
|
||||||
"next-themes": "^0.4.4",
|
"next-themes": "^0.4.4",
|
||||||
"pg": "^8.16.0",
|
"pg": "^8.16.0",
|
||||||
|
"nuqs": "^2.5.1",
|
||||||
"postgres": "^3.4.5",
|
"postgres": "^3.4.5",
|
||||||
"radix-ui": "^1.4.2",
|
"radix-ui": "^1.4.2",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
|
73
pnpm-lock.yaml
generated
73
pnpm-lock.yaml
generated
@ -266,6 +266,9 @@ importers:
|
|||||||
next-themes:
|
next-themes:
|
||||||
specifier: ^0.4.4
|
specifier: ^0.4.4
|
||||||
version: 0.4.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
version: 0.4.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
||||||
|
nuqs:
|
||||||
|
specifier: ^2.5.1
|
||||||
|
version: 2.5.1(next@15.2.1(@babel/core@7.24.5)(@opentelemetry/api@1.9.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0)
|
||||||
pg:
|
pg:
|
||||||
specifier: ^8.16.0
|
specifier: ^8.16.0
|
||||||
version: 8.16.0(pg-native@3.4.5)
|
version: 8.16.0(pg-native@3.4.5)
|
||||||
@ -516,24 +519,28 @@ packages:
|
|||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@ast-grep/napi-linux-arm64-musl@0.35.0':
|
'@ast-grep/napi-linux-arm64-musl@0.35.0':
|
||||||
resolution: {integrity: sha512-1EcvHPwyWpCL/96LuItBYGfeI5FaMTRvL+dHbO/hL5q1npqbb5qn+ppJwtNOjTPz8tayvgggxVk9T4C2O7taYA==}
|
resolution: {integrity: sha512-1EcvHPwyWpCL/96LuItBYGfeI5FaMTRvL+dHbO/hL5q1npqbb5qn+ppJwtNOjTPz8tayvgggxVk9T4C2O7taYA==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
'@ast-grep/napi-linux-x64-gnu@0.35.0':
|
'@ast-grep/napi-linux-x64-gnu@0.35.0':
|
||||||
resolution: {integrity: sha512-FDzNdlqmQnsiWXhnLxusw5AOfEcEM+5xtmrnAf3SBRFr86JyWD9qsynnFYC2pnP9hlMfifNH2TTmMpyGJW49Xw==}
|
resolution: {integrity: sha512-FDzNdlqmQnsiWXhnLxusw5AOfEcEM+5xtmrnAf3SBRFr86JyWD9qsynnFYC2pnP9hlMfifNH2TTmMpyGJW49Xw==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@ast-grep/napi-linux-x64-musl@0.35.0':
|
'@ast-grep/napi-linux-x64-musl@0.35.0':
|
||||||
resolution: {integrity: sha512-wlmndjfBafT8u5p4DBnoRQyoCSGNuVSz7rT3TqhvlHcPzUouRWMn95epU9B1LNLyjXvr9xHeRjSktyCN28w57Q==}
|
resolution: {integrity: sha512-wlmndjfBafT8u5p4DBnoRQyoCSGNuVSz7rT3TqhvlHcPzUouRWMn95epU9B1LNLyjXvr9xHeRjSktyCN28w57Q==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
'@ast-grep/napi-win32-arm64-msvc@0.35.0':
|
'@ast-grep/napi-win32-arm64-msvc@0.35.0':
|
||||||
resolution: {integrity: sha512-gkhJeYc4rrZLX2icLxalPikTLMR57DuIYLwLr9g+StHYXIsGHrbfrE6Nnbdd8Izfs34ArFCrcwdaMrGlvOPSeg==}
|
resolution: {integrity: sha512-gkhJeYc4rrZLX2icLxalPikTLMR57DuIYLwLr9g+StHYXIsGHrbfrE6Nnbdd8Izfs34ArFCrcwdaMrGlvOPSeg==}
|
||||||
@ -1040,24 +1047,28 @@ packages:
|
|||||||
engines: {node: '>=14.21.3'}
|
engines: {node: '>=14.21.3'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
'@biomejs/cli-linux-arm64@1.9.4':
|
'@biomejs/cli-linux-arm64@1.9.4':
|
||||||
resolution: {integrity: sha512-fJIW0+LYujdjUgJJuwesP4EjIBl/N/TcOX3IvIHJQNsAqvV2CHIogsmA94BPG6jZATS4Hi+xv4SkBBQSt1N4/g==}
|
resolution: {integrity: sha512-fJIW0+LYujdjUgJJuwesP4EjIBl/N/TcOX3IvIHJQNsAqvV2CHIogsmA94BPG6jZATS4Hi+xv4SkBBQSt1N4/g==}
|
||||||
engines: {node: '>=14.21.3'}
|
engines: {node: '>=14.21.3'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@biomejs/cli-linux-x64-musl@1.9.4':
|
'@biomejs/cli-linux-x64-musl@1.9.4':
|
||||||
resolution: {integrity: sha512-gEhi/jSBhZ2m6wjV530Yy8+fNqG8PAinM3oV7CyO+6c3CEh16Eizm21uHVsyVBEB6RIM8JHIl6AGYCv6Q6Q9Tg==}
|
resolution: {integrity: sha512-gEhi/jSBhZ2m6wjV530Yy8+fNqG8PAinM3oV7CyO+6c3CEh16Eizm21uHVsyVBEB6RIM8JHIl6AGYCv6Q6Q9Tg==}
|
||||||
engines: {node: '>=14.21.3'}
|
engines: {node: '>=14.21.3'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
'@biomejs/cli-linux-x64@1.9.4':
|
'@biomejs/cli-linux-x64@1.9.4':
|
||||||
resolution: {integrity: sha512-lRCJv/Vi3Vlwmbd6K+oQ0KhLHMAysN8lXoCI7XeHlxaajk06u7G+UsFSO01NAs5iYuWKmVZjmiOzJ0OJmGsMwg==}
|
resolution: {integrity: sha512-lRCJv/Vi3Vlwmbd6K+oQ0KhLHMAysN8lXoCI7XeHlxaajk06u7G+UsFSO01NAs5iYuWKmVZjmiOzJ0OJmGsMwg==}
|
||||||
engines: {node: '>=14.21.3'}
|
engines: {node: '>=14.21.3'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@biomejs/cli-win32-arm64@1.9.4':
|
'@biomejs/cli-win32-arm64@1.9.4':
|
||||||
resolution: {integrity: sha512-tlbhLk+WXZmgwoIKwHIHEBZUwxml7bRJgk0X2sPyNR3S93cdRq6XulAZRQJ17FYGGzWne0fgrXBKpl7l4M87Hg==}
|
resolution: {integrity: sha512-tlbhLk+WXZmgwoIKwHIHEBZUwxml7bRJgk0X2sPyNR3S93cdRq6XulAZRQJ17FYGGzWne0fgrXBKpl7l4M87Hg==}
|
||||||
@ -2189,67 +2200,79 @@ packages:
|
|||||||
resolution: {integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==}
|
resolution: {integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@img/sharp-libvips-linux-arm@1.0.5':
|
'@img/sharp-libvips-linux-arm@1.0.5':
|
||||||
resolution: {integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==}
|
resolution: {integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==}
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@img/sharp-libvips-linux-s390x@1.0.4':
|
'@img/sharp-libvips-linux-s390x@1.0.4':
|
||||||
resolution: {integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==}
|
resolution: {integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==}
|
||||||
cpu: [s390x]
|
cpu: [s390x]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@img/sharp-libvips-linux-x64@1.0.4':
|
'@img/sharp-libvips-linux-x64@1.0.4':
|
||||||
resolution: {integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==}
|
resolution: {integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@img/sharp-libvips-linuxmusl-arm64@1.0.4':
|
'@img/sharp-libvips-linuxmusl-arm64@1.0.4':
|
||||||
resolution: {integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==}
|
resolution: {integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
'@img/sharp-libvips-linuxmusl-x64@1.0.4':
|
'@img/sharp-libvips-linuxmusl-x64@1.0.4':
|
||||||
resolution: {integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==}
|
resolution: {integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
'@img/sharp-linux-arm64@0.33.5':
|
'@img/sharp-linux-arm64@0.33.5':
|
||||||
resolution: {integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==}
|
resolution: {integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==}
|
||||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@img/sharp-linux-arm@0.33.5':
|
'@img/sharp-linux-arm@0.33.5':
|
||||||
resolution: {integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==}
|
resolution: {integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==}
|
||||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@img/sharp-linux-s390x@0.33.5':
|
'@img/sharp-linux-s390x@0.33.5':
|
||||||
resolution: {integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==}
|
resolution: {integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==}
|
||||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
cpu: [s390x]
|
cpu: [s390x]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@img/sharp-linux-x64@0.33.5':
|
'@img/sharp-linux-x64@0.33.5':
|
||||||
resolution: {integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==}
|
resolution: {integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==}
|
||||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@img/sharp-linuxmusl-arm64@0.33.5':
|
'@img/sharp-linuxmusl-arm64@0.33.5':
|
||||||
resolution: {integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==}
|
resolution: {integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==}
|
||||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
'@img/sharp-linuxmusl-x64@0.33.5':
|
'@img/sharp-linuxmusl-x64@0.33.5':
|
||||||
resolution: {integrity: sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==}
|
resolution: {integrity: sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==}
|
||||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
'@img/sharp-wasm32@0.33.5':
|
'@img/sharp-wasm32@0.33.5':
|
||||||
resolution: {integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==}
|
resolution: {integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==}
|
||||||
@ -2353,48 +2376,56 @@ packages:
|
|||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@next/swc-linux-arm64-gnu@15.2.1':
|
'@next/swc-linux-arm64-gnu@15.2.1':
|
||||||
resolution: {integrity: sha512-gXDX5lIboebbjhiMT6kFgu4svQyjoSed6dHyjx5uZsjlvTwOAnZpn13w9XDaIMFFHw7K8CpBK7HfDKw0VZvUXQ==}
|
resolution: {integrity: sha512-gXDX5lIboebbjhiMT6kFgu4svQyjoSed6dHyjx5uZsjlvTwOAnZpn13w9XDaIMFFHw7K8CpBK7HfDKw0VZvUXQ==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@next/swc-linux-arm64-musl@15.1.2':
|
'@next/swc-linux-arm64-musl@15.1.2':
|
||||||
resolution: {integrity: sha512-9CF1Pnivij7+M3G74lxr+e9h6o2YNIe7QtExWq1KUK4hsOLTBv6FJikEwCaC3NeYTflzrm69E5UfwEAbV2U9/g==}
|
resolution: {integrity: sha512-9CF1Pnivij7+M3G74lxr+e9h6o2YNIe7QtExWq1KUK4hsOLTBv6FJikEwCaC3NeYTflzrm69E5UfwEAbV2U9/g==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
'@next/swc-linux-arm64-musl@15.2.1':
|
'@next/swc-linux-arm64-musl@15.2.1':
|
||||||
resolution: {integrity: sha512-3v0pF/adKZkBWfUffmB/ROa+QcNTrnmYG4/SS+r52HPwAK479XcWoES2I+7F7lcbqc7mTeVXrIvb4h6rR/iDKg==}
|
resolution: {integrity: sha512-3v0pF/adKZkBWfUffmB/ROa+QcNTrnmYG4/SS+r52HPwAK479XcWoES2I+7F7lcbqc7mTeVXrIvb4h6rR/iDKg==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
'@next/swc-linux-x64-gnu@15.1.2':
|
'@next/swc-linux-x64-gnu@15.1.2':
|
||||||
resolution: {integrity: sha512-tINV7WmcTUf4oM/eN3Yuu/f8jQ5C6AkueZPKeALs/qfdfX57eNv4Ij7rt0SA6iZ8+fMobVfcFVv664Op0caCCg==}
|
resolution: {integrity: sha512-tINV7WmcTUf4oM/eN3Yuu/f8jQ5C6AkueZPKeALs/qfdfX57eNv4Ij7rt0SA6iZ8+fMobVfcFVv664Op0caCCg==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@next/swc-linux-x64-gnu@15.2.1':
|
'@next/swc-linux-x64-gnu@15.2.1':
|
||||||
resolution: {integrity: sha512-RbsVq2iB6KFJRZ2cHrU67jLVLKeuOIhnQB05ygu5fCNgg8oTewxweJE8XlLV+Ii6Y6u4EHwETdUiRNXIAfpBww==}
|
resolution: {integrity: sha512-RbsVq2iB6KFJRZ2cHrU67jLVLKeuOIhnQB05ygu5fCNgg8oTewxweJE8XlLV+Ii6Y6u4EHwETdUiRNXIAfpBww==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@next/swc-linux-x64-musl@15.1.2':
|
'@next/swc-linux-x64-musl@15.1.2':
|
||||||
resolution: {integrity: sha512-jf2IseC4WRsGkzeUw/cK3wci9pxR53GlLAt30+y+B+2qAQxMw6WAC3QrANIKxkcoPU3JFh/10uFfmoMDF9JXKg==}
|
resolution: {integrity: sha512-jf2IseC4WRsGkzeUw/cK3wci9pxR53GlLAt30+y+B+2qAQxMw6WAC3QrANIKxkcoPU3JFh/10uFfmoMDF9JXKg==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
'@next/swc-linux-x64-musl@15.2.1':
|
'@next/swc-linux-x64-musl@15.2.1':
|
||||||
resolution: {integrity: sha512-QHsMLAyAIu6/fWjHmkN/F78EFPKmhQlyX5C8pRIS2RwVA7z+t9cTb0IaYWC3EHLOTjsU7MNQW+n2xGXr11QPpg==}
|
resolution: {integrity: sha512-QHsMLAyAIu6/fWjHmkN/F78EFPKmhQlyX5C8pRIS2RwVA7z+t9cTb0IaYWC3EHLOTjsU7MNQW+n2xGXr11QPpg==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
'@next/swc-win32-arm64-msvc@15.1.2':
|
'@next/swc-win32-arm64-msvc@15.1.2':
|
||||||
resolution: {integrity: sha512-wvg7MlfnaociP7k8lxLX4s2iBJm4BrNiNFhVUY+Yur5yhAJHfkS8qPPeDEUH8rQiY0PX3u/P7Q/wcg6Mv6GSAA==}
|
resolution: {integrity: sha512-wvg7MlfnaociP7k8lxLX4s2iBJm4BrNiNFhVUY+Yur5yhAJHfkS8qPPeDEUH8rQiY0PX3u/P7Q/wcg6Mv6GSAA==}
|
||||||
@ -2539,31 +2570,37 @@ packages:
|
|||||||
resolution: {integrity: sha512-BhEzNLjn4HjP8+Q18D3/jeIDBxW7OgoJYIjw2CaaysnYneoTlij8hPTKxHfyqq4IGM3fFs9TLR/k338M3zkQ7g==}
|
resolution: {integrity: sha512-BhEzNLjn4HjP8+Q18D3/jeIDBxW7OgoJYIjw2CaaysnYneoTlij8hPTKxHfyqq4IGM3fFs9TLR/k338M3zkQ7g==}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@oxc-resolver/binding-linux-arm64-musl@11.2.0':
|
'@oxc-resolver/binding-linux-arm64-musl@11.2.0':
|
||||||
resolution: {integrity: sha512-yxbMYUgRmN2V8x8XoxmD/Qq6aG7YIW3ToMDILfmcfeeRRVieEJ3DOWBT0JSE+YgrOy79OyFDH/1lO8VnqLmDQQ==}
|
resolution: {integrity: sha512-yxbMYUgRmN2V8x8XoxmD/Qq6aG7YIW3ToMDILfmcfeeRRVieEJ3DOWBT0JSE+YgrOy79OyFDH/1lO8VnqLmDQQ==}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
'@oxc-resolver/binding-linux-riscv64-gnu@11.2.0':
|
'@oxc-resolver/binding-linux-riscv64-gnu@11.2.0':
|
||||||
resolution: {integrity: sha512-QG1UfgC2N2qhW1tOnDCgB/26vn1RCshR5sYPhMeaxO1gMQ3kEKbZ3QyBXxrG1IX5qsXYj5hPDJLDYNYUjRcOpg==}
|
resolution: {integrity: sha512-QG1UfgC2N2qhW1tOnDCgB/26vn1RCshR5sYPhMeaxO1gMQ3kEKbZ3QyBXxrG1IX5qsXYj5hPDJLDYNYUjRcOpg==}
|
||||||
cpu: [riscv64]
|
cpu: [riscv64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@oxc-resolver/binding-linux-s390x-gnu@11.2.0':
|
'@oxc-resolver/binding-linux-s390x-gnu@11.2.0':
|
||||||
resolution: {integrity: sha512-uqTDsQdi6mrkSV1gvwbuT8jf/WFl6qVDVjNlx7IPSaAByrNiJfPrhTmH8b+Do58Dylz7QIRZgxQ8CHIZSyBUdg==}
|
resolution: {integrity: sha512-uqTDsQdi6mrkSV1gvwbuT8jf/WFl6qVDVjNlx7IPSaAByrNiJfPrhTmH8b+Do58Dylz7QIRZgxQ8CHIZSyBUdg==}
|
||||||
cpu: [s390x]
|
cpu: [s390x]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@oxc-resolver/binding-linux-x64-gnu@11.2.0':
|
'@oxc-resolver/binding-linux-x64-gnu@11.2.0':
|
||||||
resolution: {integrity: sha512-GZdHXhJ7p6GaQg9MjRqLebwBf8BLvGIagccI6z5yMj4fV3LU4QuDfwSEERG+R6oQ/Su9672MBqWwncvKcKT68w==}
|
resolution: {integrity: sha512-GZdHXhJ7p6GaQg9MjRqLebwBf8BLvGIagccI6z5yMj4fV3LU4QuDfwSEERG+R6oQ/Su9672MBqWwncvKcKT68w==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@oxc-resolver/binding-linux-x64-musl@11.2.0':
|
'@oxc-resolver/binding-linux-x64-musl@11.2.0':
|
||||||
resolution: {integrity: sha512-YBAC3GOicYznReG2twE7oFPSeK9Z1f507z1EYWKg6HpGYRYRlJyszViu7PrhMT85r/MumDTs429zm+CNqpFWOA==}
|
resolution: {integrity: sha512-YBAC3GOicYznReG2twE7oFPSeK9Z1f507z1EYWKg6HpGYRYRlJyszViu7PrhMT85r/MumDTs429zm+CNqpFWOA==}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
'@oxc-resolver/binding-wasm32-wasi@11.2.0':
|
'@oxc-resolver/binding-wasm32-wasi@11.2.0':
|
||||||
resolution: {integrity: sha512-+qlIg45CPVPy+Jn3vqU1zkxA/AAv6e/2Ax/ImX8usZa8Tr2JmQn/93bmSOOOnr9fXRV9d0n4JyqYzSWxWPYDEw==}
|
resolution: {integrity: sha512-+qlIg45CPVPy+Jn3vqU1zkxA/AAv6e/2Ax/ImX8usZa8Tr2JmQn/93bmSOOOnr9fXRV9d0n4JyqYzSWxWPYDEw==}
|
||||||
@ -4542,24 +4579,28 @@ packages:
|
|||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@tailwindcss/oxide-linux-arm64-musl@4.0.14':
|
'@tailwindcss/oxide-linux-arm64-musl@4.0.14':
|
||||||
resolution: {integrity: sha512-gVkJdnR/L6iIcGYXx64HGJRmlme2FGr/aZH0W6u4A3RgPMAb+6ELRLi+UBiH83RXBm9vwCfkIC/q8T51h8vUJQ==}
|
resolution: {integrity: sha512-gVkJdnR/L6iIcGYXx64HGJRmlme2FGr/aZH0W6u4A3RgPMAb+6ELRLi+UBiH83RXBm9vwCfkIC/q8T51h8vUJQ==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
'@tailwindcss/oxide-linux-x64-gnu@4.0.14':
|
'@tailwindcss/oxide-linux-x64-gnu@4.0.14':
|
||||||
resolution: {integrity: sha512-EE+EQ+c6tTpzsg+LGO1uuusjXxYx0Q00JE5ubcIGfsogSKth8n8i2BcS2wYTQe4jXGs+BQs35l78BIPzgwLddw==}
|
resolution: {integrity: sha512-EE+EQ+c6tTpzsg+LGO1uuusjXxYx0Q00JE5ubcIGfsogSKth8n8i2BcS2wYTQe4jXGs+BQs35l78BIPzgwLddw==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
'@tailwindcss/oxide-linux-x64-musl@4.0.14':
|
'@tailwindcss/oxide-linux-x64-musl@4.0.14':
|
||||||
resolution: {integrity: sha512-KCCOzo+L6XPT0oUp2Jwh233ETRQ/F6cwUnMnR0FvMUCbkDAzHbcyOgpfuAtRa5HD0WbTbH4pVD+S0pn1EhNfbw==}
|
resolution: {integrity: sha512-KCCOzo+L6XPT0oUp2Jwh233ETRQ/F6cwUnMnR0FvMUCbkDAzHbcyOgpfuAtRa5HD0WbTbH4pVD+S0pn1EhNfbw==}
|
||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
'@tailwindcss/oxide-win32-arm64-msvc@4.0.14':
|
'@tailwindcss/oxide-win32-arm64-msvc@4.0.14':
|
||||||
resolution: {integrity: sha512-AHObFiFL9lNYcm3tZSPqa/cHGpM5wOrNmM2uOMoKppp+0Hom5uuyRh0QkOp7jftsHZdrZUpmoz0Mp6vhh2XtUg==}
|
resolution: {integrity: sha512-AHObFiFL9lNYcm3tZSPqa/cHGpM5wOrNmM2uOMoKppp+0Hom5uuyRh0QkOp7jftsHZdrZUpmoz0Mp6vhh2XtUg==}
|
||||||
@ -6235,24 +6276,28 @@ packages:
|
|||||||
engines: {node: '>= 12.0.0'}
|
engines: {node: '>= 12.0.0'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
lightningcss-linux-arm64-musl@1.29.2:
|
lightningcss-linux-arm64-musl@1.29.2:
|
||||||
resolution: {integrity: sha512-Q64eM1bPlOOUgxFmoPUefqzY1yV3ctFPE6d/Vt7WzLW4rKTv7MyYNky+FWxRpLkNASTnKQUaiMJ87zNODIrrKQ==}
|
resolution: {integrity: sha512-Q64eM1bPlOOUgxFmoPUefqzY1yV3ctFPE6d/Vt7WzLW4rKTv7MyYNky+FWxRpLkNASTnKQUaiMJ87zNODIrrKQ==}
|
||||||
engines: {node: '>= 12.0.0'}
|
engines: {node: '>= 12.0.0'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
lightningcss-linux-x64-gnu@1.29.2:
|
lightningcss-linux-x64-gnu@1.29.2:
|
||||||
resolution: {integrity: sha512-0v6idDCPG6epLXtBH/RPkHvYx74CVziHo6TMYga8O2EiQApnUPZsbR9nFNrg2cgBzk1AYqEd95TlrsL7nYABQg==}
|
resolution: {integrity: sha512-0v6idDCPG6epLXtBH/RPkHvYx74CVziHo6TMYga8O2EiQApnUPZsbR9nFNrg2cgBzk1AYqEd95TlrsL7nYABQg==}
|
||||||
engines: {node: '>= 12.0.0'}
|
engines: {node: '>= 12.0.0'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [glibc]
|
||||||
|
|
||||||
lightningcss-linux-x64-musl@1.29.2:
|
lightningcss-linux-x64-musl@1.29.2:
|
||||||
resolution: {integrity: sha512-rMpz2yawkgGT8RULc5S4WiZopVMOFWjiItBT7aSfDX4NQav6M44rhn5hjtkKzB+wMTRlLLqxkeYEtQ3dd9696w==}
|
resolution: {integrity: sha512-rMpz2yawkgGT8RULc5S4WiZopVMOFWjiItBT7aSfDX4NQav6M44rhn5hjtkKzB+wMTRlLLqxkeYEtQ3dd9696w==}
|
||||||
engines: {node: '>= 12.0.0'}
|
engines: {node: '>= 12.0.0'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
libc: [musl]
|
||||||
|
|
||||||
lightningcss-win32-arm64-msvc@1.29.2:
|
lightningcss-win32-arm64-msvc@1.29.2:
|
||||||
resolution: {integrity: sha512-nL7zRW6evGQqYVu/bKGK+zShyz8OVzsCotFgc7judbt6wnB2KbiKKJwBE4SGoDBQ1O94RjW4asrCjQL4i8Fhbw==}
|
resolution: {integrity: sha512-nL7zRW6evGQqYVu/bKGK+zShyz8OVzsCotFgc7judbt6wnB2KbiKKJwBE4SGoDBQ1O94RjW4asrCjQL4i8Fhbw==}
|
||||||
@ -6752,6 +6797,27 @@ packages:
|
|||||||
resolution: {integrity: sha512-tt6PvKu4WyzPwWUzy/hvPFqn+uwXO0K1ZHka8az3NnrhWJDmSqI8ncWq0fkL0k/lmmi5tAC11FXwXuh0rFbt1A==}
|
resolution: {integrity: sha512-tt6PvKu4WyzPwWUzy/hvPFqn+uwXO0K1ZHka8az3NnrhWJDmSqI8ncWq0fkL0k/lmmi5tAC11FXwXuh0rFbt1A==}
|
||||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||||
|
|
||||||
|
nuqs@2.5.1:
|
||||||
|
resolution: {integrity: sha512-YvAyI01gaEfS6U2iTcfffKccGkqYRnGmLoCHvDjK4ShgtB0tKmYgC7+ez9PmdaiDmrLR+y1qHzfQC66T0VFwWQ==}
|
||||||
|
peerDependencies:
|
||||||
|
'@remix-run/react': '>=2'
|
||||||
|
'@tanstack/react-router': ^1
|
||||||
|
next: '>=14.2.0'
|
||||||
|
react: '>=18.2.0 || ^19.0.0-0'
|
||||||
|
react-router: ^6 || ^7
|
||||||
|
react-router-dom: ^6 || ^7
|
||||||
|
peerDependenciesMeta:
|
||||||
|
'@remix-run/react':
|
||||||
|
optional: true
|
||||||
|
'@tanstack/react-router':
|
||||||
|
optional: true
|
||||||
|
next:
|
||||||
|
optional: true
|
||||||
|
react-router:
|
||||||
|
optional: true
|
||||||
|
react-router-dom:
|
||||||
|
optional: true
|
||||||
|
|
||||||
object-assign@4.1.1:
|
object-assign@4.1.1:
|
||||||
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
|
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
@ -15410,6 +15476,13 @@ snapshots:
|
|||||||
|
|
||||||
npm-to-yarn@3.0.1: {}
|
npm-to-yarn@3.0.1: {}
|
||||||
|
|
||||||
|
nuqs@2.5.1(next@15.2.1(@babel/core@7.24.5)(@opentelemetry/api@1.9.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0):
|
||||||
|
dependencies:
|
||||||
|
'@standard-schema/spec': 1.0.0
|
||||||
|
react: 19.0.0
|
||||||
|
optionalDependencies:
|
||||||
|
next: 15.2.1(@babel/core@7.24.5)(@opentelemetry/api@1.9.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
||||||
|
|
||||||
object-assign@4.1.1: {}
|
object-assign@4.1.1: {}
|
||||||
|
|
||||||
object-inspect@1.13.4: {}
|
object-inspect@1.13.4: {}
|
||||||
|
@ -44,17 +44,30 @@ export const getCreditTransactionsAction = userActionClient
|
|||||||
const { pageIndex, pageSize, search, sorting } = parsedInput;
|
const { pageIndex, pageSize, search, sorting } = parsedInput;
|
||||||
const currentUser = (ctx as { user: User }).user;
|
const currentUser = (ctx as { user: User }).user;
|
||||||
|
|
||||||
// search by type, amount, paymentId, description, and restrict to current user
|
// Search logic: text fields use ilike, and if search is a number, also search amount fields
|
||||||
|
const searchConditions = [];
|
||||||
|
if (search) {
|
||||||
|
// Always search text fields
|
||||||
|
searchConditions.push(
|
||||||
|
ilike(creditTransaction.type, `%${search}%`),
|
||||||
|
ilike(creditTransaction.paymentId, `%${search}%`),
|
||||||
|
ilike(creditTransaction.description, `%${search}%`)
|
||||||
|
);
|
||||||
|
|
||||||
|
// If search is a valid number, also search numeric fields
|
||||||
|
const numericSearch = Number.parseInt(search, 10);
|
||||||
|
if (!Number.isNaN(numericSearch)) {
|
||||||
|
searchConditions.push(
|
||||||
|
eq(creditTransaction.amount, numericSearch),
|
||||||
|
eq(creditTransaction.remainingAmount, numericSearch)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const where = search
|
const where = search
|
||||||
? and(
|
? and(
|
||||||
eq(creditTransaction.userId, currentUser.id),
|
eq(creditTransaction.userId, currentUser.id),
|
||||||
or(
|
or(...searchConditions)
|
||||||
ilike(creditTransaction.type, `%${search}%`),
|
|
||||||
ilike(creditTransaction.amount, `%${search}%`),
|
|
||||||
ilike(creditTransaction.remainingAmount, `%${search}%`),
|
|
||||||
ilike(creditTransaction.paymentId, `%${search}%`),
|
|
||||||
ilike(creditTransaction.description, `%${search}%`)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
: eq(creditTransaction.userId, currentUser.id);
|
: eq(creditTransaction.userId, currentUser.id);
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ import { routing } from '@/i18n/routing';
|
|||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
import { type Locale, NextIntlClientProvider, hasLocale } from 'next-intl';
|
import { type Locale, NextIntlClientProvider, hasLocale } from 'next-intl';
|
||||||
import { notFound } from 'next/navigation';
|
import { notFound } from 'next/navigation';
|
||||||
|
import { NuqsAdapter } from 'nuqs/adapters/next/app';
|
||||||
import type { ReactNode } from 'react';
|
import type { ReactNode } from 'react';
|
||||||
import { Toaster } from 'sonner';
|
import { Toaster } from 'sonner';
|
||||||
import { Providers } from './providers';
|
import { Providers } from './providers';
|
||||||
@ -57,15 +58,17 @@ export default async function LocaleLayout({
|
|||||||
fontBricolageGrotesque.variable
|
fontBricolageGrotesque.variable
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<NextIntlClientProvider>
|
<NuqsAdapter>
|
||||||
<Providers locale={locale}>
|
<NextIntlClientProvider>
|
||||||
{children}
|
<Providers locale={locale}>
|
||||||
|
{children}
|
||||||
|
|
||||||
<Toaster richColors position="top-right" offset={64} />
|
<Toaster richColors position="top-right" offset={64} />
|
||||||
<TailwindIndicator />
|
<TailwindIndicator />
|
||||||
<Analytics />
|
<Analytics />
|
||||||
</Providers>
|
</Providers>
|
||||||
</NextIntlClientProvider>
|
</NextIntlClientProvider>
|
||||||
|
</NuqsAdapter>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
);
|
);
|
||||||
|
@ -4,31 +4,56 @@ import { UsersTable } from '@/components/admin/users-table';
|
|||||||
import { useUsers } from '@/hooks/use-users';
|
import { useUsers } from '@/hooks/use-users';
|
||||||
import type { SortingState } from '@tanstack/react-table';
|
import type { SortingState } from '@tanstack/react-table';
|
||||||
import { useTranslations } from 'next-intl';
|
import { useTranslations } from 'next-intl';
|
||||||
import { useState } from 'react';
|
import {
|
||||||
|
parseAsIndex,
|
||||||
|
parseAsInteger,
|
||||||
|
parseAsString,
|
||||||
|
useQueryStates,
|
||||||
|
} from 'nuqs';
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
export function UsersPageClient() {
|
export function UsersPageClient() {
|
||||||
const t = useTranslations('Dashboard.admin.users');
|
const t = useTranslations('Dashboard.admin.users');
|
||||||
const [pageIndex, setPageIndex] = useState(0);
|
|
||||||
const [pageSize, setPageSize] = useState(10);
|
|
||||||
const [search, setSearch] = useState('');
|
|
||||||
const [sorting, setSorting] = useState<SortingState>([
|
|
||||||
{ id: 'createdAt', desc: true },
|
|
||||||
]);
|
|
||||||
|
|
||||||
const { data, isLoading } = useUsers(pageIndex, pageSize, search, sorting);
|
const [{ page, pageSize, search, sortId, sortDesc }, setQueryStates] =
|
||||||
|
useQueryStates({
|
||||||
|
page: parseAsIndex.withDefault(0), // parseAsIndex adds +1 to URL, so 0-based internally, 1-based in URL
|
||||||
|
pageSize: parseAsInteger.withDefault(10),
|
||||||
|
search: parseAsString.withDefault(''),
|
||||||
|
sortId: parseAsString.withDefault('createdAt'),
|
||||||
|
sortDesc: parseAsInteger.withDefault(1),
|
||||||
|
});
|
||||||
|
|
||||||
|
const sorting: SortingState = useMemo(
|
||||||
|
() => [{ id: sortId, desc: Boolean(sortDesc) }],
|
||||||
|
[sortId, sortDesc]
|
||||||
|
);
|
||||||
|
|
||||||
|
// page is already 0-based internally thanks to parseAsIndex
|
||||||
|
const { data, isLoading } = useUsers(page, pageSize, search, sorting);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<UsersTable
|
<UsersTable
|
||||||
data={data?.items || []}
|
data={data?.items || []}
|
||||||
total={data?.total || 0}
|
total={data?.total || 0}
|
||||||
pageIndex={pageIndex}
|
pageIndex={page}
|
||||||
pageSize={pageSize}
|
pageSize={pageSize}
|
||||||
search={search}
|
search={search}
|
||||||
|
sorting={sorting}
|
||||||
loading={isLoading}
|
loading={isLoading}
|
||||||
onSearch={setSearch}
|
onSearch={(newSearch) => setQueryStates({ search: newSearch, page: 0 })}
|
||||||
onPageChange={setPageIndex}
|
onPageChange={(newPageIndex) => setQueryStates({ page: newPageIndex })}
|
||||||
onPageSizeChange={setPageSize}
|
onPageSizeChange={(newPageSize) =>
|
||||||
onSortingChange={setSorting}
|
setQueryStates({ pageSize: newPageSize, page: 0 })
|
||||||
|
}
|
||||||
|
onSortingChange={(newSorting) => {
|
||||||
|
if (newSorting.length > 0) {
|
||||||
|
setQueryStates({
|
||||||
|
sortId: newSorting[0].id,
|
||||||
|
sortDesc: newSorting[0].desc ? 1 : 0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -59,6 +59,7 @@ import { useState } from 'react';
|
|||||||
import { toast } from 'sonner';
|
import { toast } from 'sonner';
|
||||||
import { Badge } from '../ui/badge';
|
import { Badge } from '../ui/badge';
|
||||||
import { Label } from '../ui/label';
|
import { Label } from '../ui/label';
|
||||||
|
import { Skeleton } from '../ui/skeleton';
|
||||||
|
|
||||||
interface DataTableColumnHeaderProps<TData, TValue>
|
interface DataTableColumnHeaderProps<TData, TValue>
|
||||||
extends React.HTMLAttributes<HTMLDivElement> {
|
extends React.HTMLAttributes<HTMLDivElement> {
|
||||||
@ -116,12 +117,27 @@ function DataTableColumnHeader<TData, TValue>({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function TableRowSkeleton({ columns }: { columns: number }) {
|
||||||
|
return (
|
||||||
|
<TableRow>
|
||||||
|
{Array.from({ length: columns }).map((_, index) => (
|
||||||
|
<TableCell key={index} className="py-4">
|
||||||
|
<div className="flex items-center gap-2 pl-3">
|
||||||
|
<Skeleton className="h-6 w-full max-w-32" />
|
||||||
|
</div>
|
||||||
|
</TableCell>
|
||||||
|
))}
|
||||||
|
</TableRow>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
interface UsersTableProps {
|
interface UsersTableProps {
|
||||||
data: User[];
|
data: User[];
|
||||||
total: number;
|
total: number;
|
||||||
pageIndex: number;
|
pageIndex: number;
|
||||||
pageSize: number;
|
pageSize: number;
|
||||||
search: string;
|
search: string;
|
||||||
|
sorting?: SortingState;
|
||||||
loading?: boolean;
|
loading?: boolean;
|
||||||
onSearch: (search: string) => void;
|
onSearch: (search: string) => void;
|
||||||
onPageChange: (page: number) => void;
|
onPageChange: (page: number) => void;
|
||||||
@ -138,6 +154,7 @@ export function UsersTable({
|
|||||||
pageIndex,
|
pageIndex,
|
||||||
pageSize,
|
pageSize,
|
||||||
search,
|
search,
|
||||||
|
sorting = [{ id: 'createdAt', desc: true }],
|
||||||
loading,
|
loading,
|
||||||
onSearch,
|
onSearch,
|
||||||
onPageChange,
|
onPageChange,
|
||||||
@ -146,9 +163,6 @@ export function UsersTable({
|
|||||||
}: UsersTableProps) {
|
}: UsersTableProps) {
|
||||||
const t = useTranslations('Dashboard.admin.users');
|
const t = useTranslations('Dashboard.admin.users');
|
||||||
const tTable = useTranslations('Common.table');
|
const tTable = useTranslations('Common.table');
|
||||||
const [sorting, setSorting] = useState<SortingState>([
|
|
||||||
{ id: 'createdAt', desc: true },
|
|
||||||
]);
|
|
||||||
const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]);
|
const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]);
|
||||||
const [columnVisibility, setColumnVisibility] = useState<VisibilityState>({});
|
const [columnVisibility, setColumnVisibility] = useState<VisibilityState>({});
|
||||||
|
|
||||||
@ -351,7 +365,6 @@ export function UsersTable({
|
|||||||
},
|
},
|
||||||
onSortingChange: (updater) => {
|
onSortingChange: (updater) => {
|
||||||
const next = typeof updater === 'function' ? updater(sorting) : updater;
|
const next = typeof updater === 'function' ? updater(sorting) : updater;
|
||||||
setSorting(next);
|
|
||||||
onSortingChange?.(next);
|
onSortingChange?.(next);
|
||||||
},
|
},
|
||||||
onColumnFiltersChange: setColumnFilters,
|
onColumnFiltersChange: setColumnFilters,
|
||||||
@ -444,7 +457,12 @@ export function UsersTable({
|
|||||||
))}
|
))}
|
||||||
</TableHeader>
|
</TableHeader>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
{table.getRowModel().rows?.length ? (
|
{loading ? (
|
||||||
|
// Show skeleton rows while loading
|
||||||
|
Array.from({ length: pageSize }).map((_, index) => (
|
||||||
|
<TableRowSkeleton key={index} columns={columns.length} />
|
||||||
|
))
|
||||||
|
) : table.getRowModel().rows?.length ? (
|
||||||
table.getRowModel().rows.map((row) => (
|
table.getRowModel().rows.map((row) => (
|
||||||
<TableRow
|
<TableRow
|
||||||
key={row.id}
|
key={row.id}
|
||||||
@ -466,7 +484,7 @@ export function UsersTable({
|
|||||||
colSpan={columns.length}
|
colSpan={columns.length}
|
||||||
className="h-24 text-center"
|
className="h-24 text-center"
|
||||||
>
|
>
|
||||||
{loading ? tTable('loading') : tTable('noResults')}
|
{tTable('noResults')}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
)}
|
)}
|
||||||
|
@ -76,6 +76,7 @@ import { useState } from 'react';
|
|||||||
import { toast } from 'sonner';
|
import { toast } from 'sonner';
|
||||||
import { Badge } from '../../ui/badge';
|
import { Badge } from '../../ui/badge';
|
||||||
import { Label } from '../../ui/label';
|
import { Label } from '../../ui/label';
|
||||||
|
import { Skeleton } from '../../ui/skeleton';
|
||||||
|
|
||||||
// Define the credit transaction interface
|
// Define the credit transaction interface
|
||||||
export interface CreditTransaction {
|
export interface CreditTransaction {
|
||||||
@ -152,12 +153,27 @@ function DataTableColumnHeader<TData, TValue>({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function TableRowSkeleton({ columns }: { columns: number }) {
|
||||||
|
return (
|
||||||
|
<TableRow>
|
||||||
|
{Array.from({ length: columns }).map((_, index) => (
|
||||||
|
<TableCell key={index} className="py-4">
|
||||||
|
<div className="flex items-center gap-2 pl-3">
|
||||||
|
<Skeleton className="h-6 w-full max-w-32" />
|
||||||
|
</div>
|
||||||
|
</TableCell>
|
||||||
|
))}
|
||||||
|
</TableRow>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
interface CreditTransactionsTableProps {
|
interface CreditTransactionsTableProps {
|
||||||
data: CreditTransaction[];
|
data: CreditTransaction[];
|
||||||
total: number;
|
total: number;
|
||||||
pageIndex: number;
|
pageIndex: number;
|
||||||
pageSize: number;
|
pageSize: number;
|
||||||
search: string;
|
search: string;
|
||||||
|
sorting?: SortingState;
|
||||||
loading?: boolean;
|
loading?: boolean;
|
||||||
onSearch: (search: string) => void;
|
onSearch: (search: string) => void;
|
||||||
onPageChange: (page: number) => void;
|
onPageChange: (page: number) => void;
|
||||||
@ -171,6 +187,7 @@ export function CreditTransactionsTable({
|
|||||||
pageIndex,
|
pageIndex,
|
||||||
pageSize,
|
pageSize,
|
||||||
search,
|
search,
|
||||||
|
sorting = [{ id: 'createdAt', desc: true }],
|
||||||
loading,
|
loading,
|
||||||
onSearch,
|
onSearch,
|
||||||
onPageChange,
|
onPageChange,
|
||||||
@ -179,9 +196,6 @@ export function CreditTransactionsTable({
|
|||||||
}: CreditTransactionsTableProps) {
|
}: CreditTransactionsTableProps) {
|
||||||
const t = useTranslations('Dashboard.settings.credits.transactions');
|
const t = useTranslations('Dashboard.settings.credits.transactions');
|
||||||
const tTable = useTranslations('Common.table');
|
const tTable = useTranslations('Common.table');
|
||||||
const [sorting, setSorting] = useState<SortingState>([
|
|
||||||
{ id: 'createdAt', desc: true },
|
|
||||||
]);
|
|
||||||
const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]);
|
const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]);
|
||||||
const [columnVisibility, setColumnVisibility] = useState<VisibilityState>({});
|
const [columnVisibility, setColumnVisibility] = useState<VisibilityState>({});
|
||||||
|
|
||||||
@ -449,7 +463,6 @@ export function CreditTransactionsTable({
|
|||||||
},
|
},
|
||||||
onSortingChange: (updater) => {
|
onSortingChange: (updater) => {
|
||||||
const next = typeof updater === 'function' ? updater(sorting) : updater;
|
const next = typeof updater === 'function' ? updater(sorting) : updater;
|
||||||
setSorting(next);
|
|
||||||
onSortingChange?.(next);
|
onSortingChange?.(next);
|
||||||
},
|
},
|
||||||
onColumnFiltersChange: setColumnFilters,
|
onColumnFiltersChange: setColumnFilters,
|
||||||
@ -538,7 +551,12 @@ export function CreditTransactionsTable({
|
|||||||
))}
|
))}
|
||||||
</TableHeader>
|
</TableHeader>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
{table.getRowModel().rows?.length ? (
|
{loading ? (
|
||||||
|
// Show skeleton rows while loading
|
||||||
|
Array.from({ length: pageSize }).map((_, index) => (
|
||||||
|
<TableRowSkeleton key={index} columns={columns.length} />
|
||||||
|
))
|
||||||
|
) : table.getRowModel().rows?.length ? (
|
||||||
table.getRowModel().rows.map((row) => (
|
table.getRowModel().rows.map((row) => (
|
||||||
<TableRow
|
<TableRow
|
||||||
key={row.id}
|
key={row.id}
|
||||||
@ -560,7 +578,7 @@ export function CreditTransactionsTable({
|
|||||||
colSpan={columns.length}
|
colSpan={columns.length}
|
||||||
className="h-24 text-center"
|
className="h-24 text-center"
|
||||||
>
|
>
|
||||||
{loading ? tTable('loading') : tTable('noResults')}
|
{tTable('noResults')}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
)}
|
)}
|
||||||
|
@ -4,22 +4,36 @@ import { CreditTransactionsTable } from '@/components/settings/credits/credit-tr
|
|||||||
import { useCreditTransactions } from '@/hooks/use-credits';
|
import { useCreditTransactions } from '@/hooks/use-credits';
|
||||||
import type { SortingState } from '@tanstack/react-table';
|
import type { SortingState } from '@tanstack/react-table';
|
||||||
import { useTranslations } from 'next-intl';
|
import { useTranslations } from 'next-intl';
|
||||||
import { useState } from 'react';
|
import {
|
||||||
|
parseAsIndex,
|
||||||
|
parseAsInteger,
|
||||||
|
parseAsString,
|
||||||
|
useQueryStates,
|
||||||
|
} from 'nuqs';
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Credit transactions component
|
* Credit transactions component
|
||||||
*/
|
*/
|
||||||
export function CreditTransactions() {
|
export function CreditTransactions() {
|
||||||
const t = useTranslations('Dashboard.settings.credits.transactions');
|
const t = useTranslations('Dashboard.settings.credits.transactions');
|
||||||
const [pageIndex, setPageIndex] = useState(0);
|
|
||||||
const [pageSize, setPageSize] = useState(10);
|
const [{ page, pageSize, search, sortId, sortDesc }, setQueryStates] =
|
||||||
const [search, setSearch] = useState('');
|
useQueryStates({
|
||||||
const [sorting, setSorting] = useState<SortingState>([
|
page: parseAsIndex.withDefault(0), // 0-based internally, 1-based in URL
|
||||||
{ id: 'createdAt', desc: true },
|
pageSize: parseAsInteger.withDefault(10),
|
||||||
]);
|
search: parseAsString.withDefault(''),
|
||||||
|
sortId: parseAsString.withDefault('createdAt'),
|
||||||
|
sortDesc: parseAsInteger.withDefault(1),
|
||||||
|
});
|
||||||
|
|
||||||
|
const sorting: SortingState = useMemo(
|
||||||
|
() => [{ id: sortId, desc: Boolean(sortDesc) }],
|
||||||
|
[sortId, sortDesc]
|
||||||
|
);
|
||||||
|
|
||||||
const { data, isLoading } = useCreditTransactions(
|
const { data, isLoading } = useCreditTransactions(
|
||||||
pageIndex,
|
page,
|
||||||
pageSize,
|
pageSize,
|
||||||
search,
|
search,
|
||||||
sorting
|
sorting
|
||||||
@ -29,14 +43,24 @@ export function CreditTransactions() {
|
|||||||
<CreditTransactionsTable
|
<CreditTransactionsTable
|
||||||
data={data?.items || []}
|
data={data?.items || []}
|
||||||
total={data?.total || 0}
|
total={data?.total || 0}
|
||||||
pageIndex={pageIndex}
|
pageIndex={page}
|
||||||
pageSize={pageSize}
|
pageSize={pageSize}
|
||||||
search={search}
|
search={search}
|
||||||
|
sorting={sorting}
|
||||||
loading={isLoading}
|
loading={isLoading}
|
||||||
onSearch={setSearch}
|
onSearch={(newSearch) => setQueryStates({ search: newSearch, page: 0 })}
|
||||||
onPageChange={setPageIndex}
|
onPageChange={(newPageIndex) => setQueryStates({ page: newPageIndex })}
|
||||||
onPageSizeChange={setPageSize}
|
onPageSizeChange={(newPageSize) =>
|
||||||
onSortingChange={setSorting}
|
setQueryStates({ pageSize: newPageSize, page: 0 })
|
||||||
|
}
|
||||||
|
onSortingChange={(newSorting) => {
|
||||||
|
if (newSorting.length > 0) {
|
||||||
|
setQueryStates({
|
||||||
|
sortId: newSorting[0].id,
|
||||||
|
sortDesc: newSorting[0].desc ? 1 : 0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import { CreditTransactions } from '@/components/settings/credits/credit-transac
|
|||||||
import CreditsBalanceCard from '@/components/settings/credits/credits-balance-card';
|
import CreditsBalanceCard from '@/components/settings/credits/credits-balance-card';
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||||
import { useTranslations } from 'next-intl';
|
import { useTranslations } from 'next-intl';
|
||||||
|
import { parseAsStringLiteral, useQueryState } from 'nuqs';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Credits page client, show credit balance and transactions
|
* Credits page client, show credit balance and transactions
|
||||||
@ -12,9 +13,24 @@ import { useTranslations } from 'next-intl';
|
|||||||
export default function CreditsPageClient() {
|
export default function CreditsPageClient() {
|
||||||
const t = useTranslations('Dashboard.settings.credits');
|
const t = useTranslations('Dashboard.settings.credits');
|
||||||
|
|
||||||
|
const [activeTab, setActiveTab] = useQueryState(
|
||||||
|
'tab',
|
||||||
|
parseAsStringLiteral(['balance', 'transactions']).withDefault('balance')
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleTabChange = (value: string) => {
|
||||||
|
if (value === 'balance' || value === 'transactions') {
|
||||||
|
setActiveTab(value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col gap-8">
|
<div className="flex flex-col gap-8">
|
||||||
<Tabs defaultValue="balance" className="w-full">
|
<Tabs
|
||||||
|
value={activeTab}
|
||||||
|
onValueChange={handleTabChange}
|
||||||
|
className="w-full"
|
||||||
|
>
|
||||||
<TabsList className="">
|
<TabsList className="">
|
||||||
<TabsTrigger value="balance">{t('tabs.balance')}</TabsTrigger>
|
<TabsTrigger value="balance">{t('tabs.balance')}</TabsTrigger>
|
||||||
<TabsTrigger value="transactions">
|
<TabsTrigger value="transactions">
|
||||||
|
Loading…
Reference in New Issue
Block a user