Release 202507031255
This commit is contained in:
3
.vscode/extensions.json
vendored
3
.vscode/extensions.json
vendored
@@ -7,7 +7,8 @@
|
|||||||
"golang.go",
|
"golang.go",
|
||||||
"bradlc.vscode-tailwindcss",
|
"bradlc.vscode-tailwindcss",
|
||||||
"craigrbroughton.htmx-attributes",
|
"craigrbroughton.htmx-attributes",
|
||||||
"nefrob.vscode-just-syntax"
|
"nefrob.vscode-just-syntax",
|
||||||
|
"prisma.prisma"
|
||||||
],
|
],
|
||||||
"unwantedRecommendations": []
|
"unwantedRecommendations": []
|
||||||
}
|
}
|
||||||
|
|||||||
50
web/package-lock.json
generated
50
web/package-lock.json
generated
@@ -11,7 +11,7 @@
|
|||||||
"@astrojs/check": "0.9.4",
|
"@astrojs/check": "0.9.4",
|
||||||
"@astrojs/db": "0.15.0",
|
"@astrojs/db": "0.15.0",
|
||||||
"@astrojs/mdx": "4.3.0",
|
"@astrojs/mdx": "4.3.0",
|
||||||
"@astrojs/node": "9.2.2",
|
"@astrojs/node": "9.3.0",
|
||||||
"@astrojs/rss": "4.0.12",
|
"@astrojs/rss": "4.0.12",
|
||||||
"@astrojs/sitemap": "3.4.1",
|
"@astrojs/sitemap": "3.4.1",
|
||||||
"@fontsource-variable/space-grotesk": "5.2.8",
|
"@fontsource-variable/space-grotesk": "5.2.8",
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
"@types/mime-types": "3.0.1",
|
"@types/mime-types": "3.0.1",
|
||||||
"@types/pg": "8.15.4",
|
"@types/pg": "8.15.4",
|
||||||
"@vercel/og": "0.6.8",
|
"@vercel/og": "0.6.8",
|
||||||
"astro": "5.10.1",
|
"astro": "5.11.0",
|
||||||
"astro-loading-indicator": "0.7.0",
|
"astro-loading-indicator": "0.7.0",
|
||||||
"astro-remote": "0.3.4",
|
"astro-remote": "0.3.4",
|
||||||
"astro-seo-schema": "5.0.0",
|
"astro-seo-schema": "5.0.0",
|
||||||
@@ -51,8 +51,8 @@
|
|||||||
"web-push": "3.6.7"
|
"web-push": "3.6.7"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "9.30.0",
|
"@eslint/js": "9.30.1",
|
||||||
"@faker-js/faker": "9.8.0",
|
"@faker-js/faker": "9.9.0",
|
||||||
"@iconify-json/material-symbols": "1.2.28",
|
"@iconify-json/material-symbols": "1.2.28",
|
||||||
"@iconify-json/mdi": "1.2.3",
|
"@iconify-json/mdi": "1.2.3",
|
||||||
"@iconify-json/ri": "1.2.5",
|
"@iconify-json/ri": "1.2.5",
|
||||||
@@ -72,12 +72,12 @@
|
|||||||
"astro-icon": "1.1.5",
|
"astro-icon": "1.1.5",
|
||||||
"date-fns": "4.1.0",
|
"date-fns": "4.1.0",
|
||||||
"esbuild": "0.25.5",
|
"esbuild": "0.25.5",
|
||||||
"eslint": "9.30.0",
|
"eslint": "9.30.1",
|
||||||
"eslint-import-resolver-typescript": "4.4.4",
|
"eslint-import-resolver-typescript": "4.4.4",
|
||||||
"eslint-plugin-astro": "1.3.1",
|
"eslint-plugin-astro": "1.3.1",
|
||||||
"eslint-plugin-import": "2.32.0",
|
"eslint-plugin-import": "2.32.0",
|
||||||
"eslint-plugin-jsx-a11y": "6.10.2",
|
"eslint-plugin-jsx-a11y": "6.10.2",
|
||||||
"globals": "16.2.0",
|
"globals": "16.3.0",
|
||||||
"prettier": "3.6.2",
|
"prettier": "3.6.2",
|
||||||
"prettier-plugin-astro": "0.14.1",
|
"prettier-plugin-astro": "0.14.1",
|
||||||
"prettier-plugin-tailwindcss": "0.6.13",
|
"prettier-plugin-tailwindcss": "0.6.13",
|
||||||
@@ -297,9 +297,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@astrojs/node": {
|
"node_modules/@astrojs/node": {
|
||||||
"version": "9.2.2",
|
"version": "9.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/@astrojs/node/-/node-9.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/@astrojs/node/-/node-9.3.0.tgz",
|
||||||
"integrity": "sha512-PtLPuuojmcl9O3CEvXqL/D+wB4x5DlbrGOvP0MeTAh/VfKFprYAzgw1+45xsnTO+QvPWb26l1cT+ZQvvohmvMw==",
|
"integrity": "sha512-IV8NzGStHAsKBz1ljxxD8PBhBfnw/BEx/PZfsncTNXg9D4kQtZbSy+Ak0LvDs+rPmK0VeXLNn0HAdWuHCVg8cw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/internal-helpers": "0.6.1",
|
"@astrojs/internal-helpers": "0.6.1",
|
||||||
@@ -2641,9 +2641,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@eslint/js": {
|
"node_modules/@eslint/js": {
|
||||||
"version": "9.30.0",
|
"version": "9.30.1",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.30.0.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.30.1.tgz",
|
||||||
"integrity": "sha512-Wzw3wQwPvc9sHM+NjakWTcPx11mbZyiYHuwWa/QfZ7cIRX7WK54PSk7bdyXDaoaopUcMatv1zaQvOAAO8hCdww==",
|
"integrity": "sha512-zXhuECFlyep42KZUhWjfvsmXGX39W8K8LFb8AWXM9gSV9dQB+MrJGLKvW6Zw0Ggnbpw0VHTtrhFXYe3Gym18jg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -2678,9 +2678,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@faker-js/faker": {
|
"node_modules/@faker-js/faker": {
|
||||||
"version": "9.8.0",
|
"version": "9.9.0",
|
||||||
"resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-9.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-9.9.0.tgz",
|
||||||
"integrity": "sha512-U9wpuSrJC93jZBxx/Qq2wPjCuYISBueyVUGK7qqdmj7r/nxaxwW8AQDCLeRO7wZnjj94sh3p246cAYjUKuqgfg==",
|
"integrity": "sha512-OEl393iCOoo/z8bMezRlJu+GlRGlsKbUAN7jKB6LhnKoqKve5DXRpalbItIIcwnCjs1k/FOPjFzcA6Qn+H+YbA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@@ -6333,9 +6333,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/astro": {
|
"node_modules/astro": {
|
||||||
"version": "5.10.1",
|
"version": "5.11.0",
|
||||||
"resolved": "https://registry.npmjs.org/astro/-/astro-5.10.1.tgz",
|
"resolved": "https://registry.npmjs.org/astro/-/astro-5.11.0.tgz",
|
||||||
"integrity": "sha512-DJVmt+51jU1xmgmAHCDwuUgcG/5aVFSU+tcX694acAZqPVt8EMUAmUZcJDX36Z7/EztnPph9HR3pm72jS2EgHQ==",
|
"integrity": "sha512-MEICntERthUxJPSSDsDiZuwiCMrsaYy3fnDhp4c6ScUfldCB8RBnB/myYdpTFXpwYBy6SgVsHQ1H4MuuA7ro/Q==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/compiler": "^2.12.2",
|
"@astrojs/compiler": "^2.12.2",
|
||||||
@@ -9039,9 +9039,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint": {
|
"node_modules/eslint": {
|
||||||
"version": "9.30.0",
|
"version": "9.30.1",
|
||||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.30.0.tgz",
|
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.30.1.tgz",
|
||||||
"integrity": "sha512-iN/SiPxmQu6EVkf+m1qpBxzUhE12YqFLOSySuOyVLJLEF9nzTf+h/1AJYc1JWzCnktggeNrjvQGLngDzXirU6g==",
|
"integrity": "sha512-zmxXPNMOXmwm9E0yQLi5uqXHs7uq2UIiqEKo3Gq+3fwo1XrJ+hijAZImyF7hclW3E6oHz43Yk3RP8at6OTKflQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -9051,7 +9051,7 @@
|
|||||||
"@eslint/config-helpers": "^0.3.0",
|
"@eslint/config-helpers": "^0.3.0",
|
||||||
"@eslint/core": "^0.14.0",
|
"@eslint/core": "^0.14.0",
|
||||||
"@eslint/eslintrc": "^3.3.1",
|
"@eslint/eslintrc": "^3.3.1",
|
||||||
"@eslint/js": "9.30.0",
|
"@eslint/js": "9.30.1",
|
||||||
"@eslint/plugin-kit": "^0.3.1",
|
"@eslint/plugin-kit": "^0.3.1",
|
||||||
"@humanfs/node": "^0.16.6",
|
"@humanfs/node": "^0.16.6",
|
||||||
"@humanwhocodes/module-importer": "^1.0.1",
|
"@humanwhocodes/module-importer": "^1.0.1",
|
||||||
@@ -10401,9 +10401,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/globals": {
|
"node_modules/globals": {
|
||||||
"version": "16.2.0",
|
"version": "16.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/globals/-/globals-16.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/globals/-/globals-16.3.0.tgz",
|
||||||
"integrity": "sha512-O+7l9tPdHCU320IigZZPj5zmRCFG9xHmx9cU8FqU2Rp+JN714seHV+2S9+JslCpY4gJwU2vOGox0wzgae/MCEg==",
|
"integrity": "sha512-bqWEnJ1Nt3neqx2q5SFfGS8r/ahumIakg3HcwtNlrVlwXIeNumWn/c7Pn/wKzGhf6SaW6H6uWXLqC30STCMchQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
"@astrojs/check": "0.9.4",
|
"@astrojs/check": "0.9.4",
|
||||||
"@astrojs/db": "0.15.0",
|
"@astrojs/db": "0.15.0",
|
||||||
"@astrojs/mdx": "4.3.0",
|
"@astrojs/mdx": "4.3.0",
|
||||||
"@astrojs/node": "9.2.2",
|
"@astrojs/node": "9.3.0",
|
||||||
"@astrojs/rss": "4.0.12",
|
"@astrojs/rss": "4.0.12",
|
||||||
"@astrojs/sitemap": "3.4.1",
|
"@astrojs/sitemap": "3.4.1",
|
||||||
"@fontsource-variable/space-grotesk": "5.2.8",
|
"@fontsource-variable/space-grotesk": "5.2.8",
|
||||||
@@ -38,7 +38,7 @@
|
|||||||
"@types/mime-types": "3.0.1",
|
"@types/mime-types": "3.0.1",
|
||||||
"@types/pg": "8.15.4",
|
"@types/pg": "8.15.4",
|
||||||
"@vercel/og": "0.6.8",
|
"@vercel/og": "0.6.8",
|
||||||
"astro": "5.10.1",
|
"astro": "5.11.0",
|
||||||
"astro-loading-indicator": "0.7.0",
|
"astro-loading-indicator": "0.7.0",
|
||||||
"astro-remote": "0.3.4",
|
"astro-remote": "0.3.4",
|
||||||
"astro-seo-schema": "5.0.0",
|
"astro-seo-schema": "5.0.0",
|
||||||
@@ -67,8 +67,8 @@
|
|||||||
"web-push": "3.6.7"
|
"web-push": "3.6.7"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "9.30.0",
|
"@eslint/js": "9.30.1",
|
||||||
"@faker-js/faker": "9.8.0",
|
"@faker-js/faker": "9.9.0",
|
||||||
"@iconify-json/material-symbols": "1.2.28",
|
"@iconify-json/material-symbols": "1.2.28",
|
||||||
"@iconify-json/mdi": "1.2.3",
|
"@iconify-json/mdi": "1.2.3",
|
||||||
"@iconify-json/ri": "1.2.5",
|
"@iconify-json/ri": "1.2.5",
|
||||||
@@ -88,12 +88,12 @@
|
|||||||
"astro-icon": "1.1.5",
|
"astro-icon": "1.1.5",
|
||||||
"date-fns": "4.1.0",
|
"date-fns": "4.1.0",
|
||||||
"esbuild": "0.25.5",
|
"esbuild": "0.25.5",
|
||||||
"eslint": "9.30.0",
|
"eslint": "9.30.1",
|
||||||
"eslint-import-resolver-typescript": "4.4.4",
|
"eslint-import-resolver-typescript": "4.4.4",
|
||||||
"eslint-plugin-astro": "1.3.1",
|
"eslint-plugin-astro": "1.3.1",
|
||||||
"eslint-plugin-import": "2.32.0",
|
"eslint-plugin-import": "2.32.0",
|
||||||
"eslint-plugin-jsx-a11y": "6.10.2",
|
"eslint-plugin-jsx-a11y": "6.10.2",
|
||||||
"globals": "16.2.0",
|
"globals": "16.3.0",
|
||||||
"prettier": "3.6.2",
|
"prettier": "3.6.2",
|
||||||
"prettier-plugin-astro": "0.14.1",
|
"prettier-plugin-astro": "0.14.1",
|
||||||
"prettier-plugin-tailwindcss": "0.6.13",
|
"prettier-plugin-tailwindcss": "0.6.13",
|
||||||
|
|||||||
@@ -275,7 +275,7 @@ CREATE OR REPLACE FUNCTION handle_suggestion_status_change()
|
|||||||
RETURNS TRIGGER AS $$
|
RETURNS TRIGGER AS $$
|
||||||
DECLARE
|
DECLARE
|
||||||
service_name TEXT;
|
service_name TEXT;
|
||||||
service_visibility "serviceVisibility";
|
service_visibility "ServiceVisibility";
|
||||||
is_user_admin_or_moderator BOOLEAN;
|
is_user_admin_or_moderator BOOLEAN;
|
||||||
BEGIN
|
BEGIN
|
||||||
-- Award karma for first approval
|
-- Award karma for first approval
|
||||||
@@ -283,7 +283,7 @@ BEGIN
|
|||||||
-- and ensure it wasn't already APPROVED.
|
-- and ensure it wasn't already APPROVED.
|
||||||
IF OLD.status IS DISTINCT FROM 'APPROVED' AND NEW.status = 'APPROVED' THEN
|
IF OLD.status IS DISTINCT FROM 'APPROVED' AND NEW.status = 'APPROVED' THEN
|
||||||
-- Fetch service details for the description
|
-- Fetch service details for the description
|
||||||
SELECT name, serviceVisibility INTO service_name, service_visibility FROM "Service" WHERE id = NEW."serviceId";
|
SELECT name, "serviceVisibility" INTO service_name, service_visibility FROM "Service" WHERE id = NEW."serviceId";
|
||||||
|
|
||||||
-- Only award karma if the service is public
|
-- Only award karma if the service is public
|
||||||
IF service_visibility = 'PUBLIC' THEN
|
IF service_visibility = 'PUBLIC' THEN
|
||||||
|
|||||||
33
web/src/constants/readStatus.ts
Normal file
33
web/src/constants/readStatus.ts
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import { makeHelpersForOptions } from '../lib/makeHelpersForOptions'
|
||||||
|
import { transformCase } from '../lib/strings'
|
||||||
|
|
||||||
|
type ReadStatusInfo<T extends string | null | undefined = string> = {
|
||||||
|
id: T
|
||||||
|
label: string
|
||||||
|
readValue: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export const {
|
||||||
|
dataArray: readStatuses,
|
||||||
|
getFn: getReadStatus,
|
||||||
|
zodEnumById: readStatusZodEnum,
|
||||||
|
} = makeHelpersForOptions(
|
||||||
|
'id',
|
||||||
|
(id): ReadStatusInfo<typeof id> => ({
|
||||||
|
id,
|
||||||
|
label: id ? transformCase(id, 'title') : String(id),
|
||||||
|
readValue: false,
|
||||||
|
}),
|
||||||
|
[
|
||||||
|
{
|
||||||
|
id: 'unread',
|
||||||
|
label: 'Unread',
|
||||||
|
readValue: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'read',
|
||||||
|
label: 'Read',
|
||||||
|
readValue: true,
|
||||||
|
},
|
||||||
|
] as const satisfies ReadStatusInfo[]
|
||||||
|
)
|
||||||
@@ -5,10 +5,12 @@ import { actions } from 'astro:actions'
|
|||||||
|
|
||||||
import Button from '../components/Button.astro'
|
import Button from '../components/Button.astro'
|
||||||
import CopyButton from '../components/CopyButton.astro'
|
import CopyButton from '../components/CopyButton.astro'
|
||||||
|
import Pagination from '../components/Pagination.astro'
|
||||||
import PushNotificationBanner from '../components/PushNotificationBanner.astro'
|
import PushNotificationBanner from '../components/PushNotificationBanner.astro'
|
||||||
import TimeFormatted from '../components/TimeFormatted.astro'
|
import TimeFormatted from '../components/TimeFormatted.astro'
|
||||||
import Tooltip from '../components/Tooltip.astro'
|
import Tooltip from '../components/Tooltip.astro'
|
||||||
import { getNotificationTypeInfo } from '../constants/notificationTypes'
|
import { getNotificationTypeInfo } from '../constants/notificationTypes'
|
||||||
|
import { getReadStatus, readStatusZodEnum } from '../constants/readStatus'
|
||||||
import BaseLayout from '../layouts/BaseLayout.astro'
|
import BaseLayout from '../layouts/BaseLayout.astro'
|
||||||
import { cn } from '../lib/cn'
|
import { cn } from '../lib/cn'
|
||||||
import { getOrCreateNotificationPreferences } from '../lib/notificationPreferences'
|
import { getOrCreateNotificationPreferences } from '../lib/notificationPreferences'
|
||||||
@@ -16,6 +18,10 @@ import { makeNotificationActions, makeNotificationContent, makeNotificationTitle
|
|||||||
import { zodParseQueryParamsStoringErrors } from '../lib/parseUrlFilters'
|
import { zodParseQueryParamsStoringErrors } from '../lib/parseUrlFilters'
|
||||||
import { prisma } from '../lib/prisma'
|
import { prisma } from '../lib/prisma'
|
||||||
import { makeLoginUrl } from '../lib/redirectUrls'
|
import { makeLoginUrl } from '../lib/redirectUrls'
|
||||||
|
import { transformCase } from '../lib/strings'
|
||||||
|
import { urlWithParams } from '../lib/urls'
|
||||||
|
|
||||||
|
import type { Prisma } from '@prisma/client'
|
||||||
|
|
||||||
const user = Astro.locals.user
|
const user = Astro.locals.user
|
||||||
if (!user) return Astro.redirect(makeLoginUrl(Astro.url))
|
if (!user) return Astro.redirect(makeLoginUrl(Astro.url))
|
||||||
@@ -25,20 +31,26 @@ const PAGE_SIZE = 20
|
|||||||
const { data: params } = zodParseQueryParamsStoringErrors(
|
const { data: params } = zodParseQueryParamsStoringErrors(
|
||||||
{
|
{
|
||||||
page: z.coerce.number().int().min(1).default(1),
|
page: z.coerce.number().int().min(1).default(1),
|
||||||
|
readStatus: readStatusZodEnum.optional(),
|
||||||
},
|
},
|
||||||
Astro
|
Astro
|
||||||
)
|
)
|
||||||
const skip = (params.page - 1) * PAGE_SIZE
|
const skip = (params.page - 1) * PAGE_SIZE
|
||||||
|
|
||||||
|
const readStatusInfo = params.readStatus ? getReadStatus(params.readStatus) : undefined
|
||||||
|
|
||||||
|
const notificationWhereClause: Prisma.NotificationWhereInput = {
|
||||||
|
userId: user.id,
|
||||||
|
read: readStatusInfo?.readValue,
|
||||||
|
}
|
||||||
|
|
||||||
const [dbNotifications, notificationPreferences, totalNotifications, pushSubscriptions] =
|
const [dbNotifications, notificationPreferences, totalNotifications, pushSubscriptions] =
|
||||||
await Astro.locals.banners.tryMany([
|
await Astro.locals.banners.tryMany([
|
||||||
[
|
[
|
||||||
'Error while fetching notifications',
|
'Error while fetching notifications',
|
||||||
() =>
|
() =>
|
||||||
prisma.notification.findMany({
|
prisma.notification.findMany({
|
||||||
where: {
|
where: notificationWhereClause,
|
||||||
userId: user.id,
|
|
||||||
},
|
|
||||||
orderBy: {
|
orderBy: {
|
||||||
createdAt: 'desc',
|
createdAt: 'desc',
|
||||||
},
|
},
|
||||||
@@ -153,7 +165,7 @@ const [dbNotifications, notificationPreferences, totalNotifications, pushSubscri
|
|||||||
],
|
],
|
||||||
[
|
[
|
||||||
'Error while fetching total notifications',
|
'Error while fetching total notifications',
|
||||||
() => prisma.notification.count({ where: { userId: user.id } }),
|
() => prisma.notification.count({ where: notificationWhereClause }),
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
@@ -227,13 +239,18 @@ const notifications = dbNotifications.map((notification) => ({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
<div class="mb-4 flex items-center justify-between">
|
<div class="xs:flex-row xs:flex-wrap mb-4 flex flex-col items-center justify-between gap-2">
|
||||||
<h1 class="font-title flex items-center text-2xl leading-tight font-bold tracking-wider">
|
<h1 class="font-title flex items-center text-2xl leading-tight font-bold tracking-wider">
|
||||||
<Icon name="ri:notification-line" class="mr-2 size-6 text-zinc-400" />
|
<Icon name="ri:notification-line" class="mr-2 size-6 text-zinc-400" />
|
||||||
Notifications
|
|
||||||
|
{transformCase(`${readStatusInfo?.label ?? ''} notifications`.trim(), 'sentence')}
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<form method="POST" action={actions.notification.updateReadStatus}>
|
<form
|
||||||
|
method="POST"
|
||||||
|
action={actions.notification.updateReadStatus}
|
||||||
|
class="xs:justify-start flex flex-1 flex-row-reverse flex-wrap items-center justify-center gap-2"
|
||||||
|
>
|
||||||
<input type="hidden" name="notificationId" value="all" />
|
<input type="hidden" name="notificationId" value="all" />
|
||||||
<input type="hidden" name="read" value="true" />
|
<input type="hidden" name="read" value="true" />
|
||||||
<Button
|
<Button
|
||||||
@@ -243,6 +260,25 @@ const notifications = dbNotifications.map((notification) => ({
|
|||||||
disabled={notifications.length === 0}
|
disabled={notifications.length === 0}
|
||||||
color="white"
|
color="white"
|
||||||
/>
|
/>
|
||||||
|
{
|
||||||
|
params.readStatus === 'unread' ? (
|
||||||
|
<Button
|
||||||
|
as="a"
|
||||||
|
href={urlWithParams(Astro.url, { readStatus: null }, { clearExisting: true })}
|
||||||
|
label="See all"
|
||||||
|
icon="ri:eye-line"
|
||||||
|
color="black"
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<Button
|
||||||
|
as="a"
|
||||||
|
href={urlWithParams(Astro.url, { readStatus: 'unread' }, { clearExisting: true })}
|
||||||
|
label="See unread only"
|
||||||
|
icon="ri:eye-off-line"
|
||||||
|
color="black"
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -323,31 +359,12 @@ const notifications = dbNotifications.map((notification) => ({
|
|||||||
))}
|
))}
|
||||||
|
|
||||||
{totalPages > 1 && (
|
{totalPages > 1 && (
|
||||||
<div class="mt-8 flex justify-center gap-4">
|
<Pagination
|
||||||
<form method="GET" action="/notifications" class="inline">
|
currentPage={params.page}
|
||||||
<input type="hidden" name="page" value={params.page - 1} />
|
totalPages={totalPages}
|
||||||
<button
|
currentUrl={Astro.url}
|
||||||
type="submit"
|
class="mt-8"
|
||||||
class="rounded-md border border-zinc-700 bg-zinc-800 px-4 py-2 text-sm text-zinc-200 transition-colors duration-200 hover:bg-zinc-700"
|
/>
|
||||||
disabled={params.page <= 1}
|
|
||||||
>
|
|
||||||
Previous
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
<span class="inline-flex items-center px-2 text-sm text-zinc-400">
|
|
||||||
Page {params.page} of {totalPages}
|
|
||||||
</span>
|
|
||||||
<form method="GET" action="/notifications" class="inline">
|
|
||||||
<input type="hidden" name="page" value={params.page + 1} />
|
|
||||||
<button
|
|
||||||
type="submit"
|
|
||||||
class="rounded-md border border-zinc-700 bg-zinc-800 px-4 py-2 text-sm text-zinc-200 transition-colors duration-200 hover:bg-zinc-700"
|
|
||||||
disabled={params.page >= totalPages}
|
|
||||||
>
|
|
||||||
Next
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user