From dabc4e5c478d9a2e424be2f7b21375040a4c655f Mon Sep 17 00:00:00 2001 From: pluja Date: Tue, 20 May 2025 08:02:55 +0000 Subject: [PATCH] donation component --- web/package-lock.json | 264 +++++++- web/package.json | 4 +- web/src/components/AnnouncementBanner.astro | 79 +-- web/src/components/DonationAddress.astro | 60 ++ web/src/constants/announcementTypes.ts | 65 ++ web/src/pages/{about.md => about.mdx} | 14 +- web/src/pages/admin/announcements/index.astro | 589 ++++++++---------- web/src/pages/index.astro | 39 +- 8 files changed, 717 insertions(+), 397 deletions(-) create mode 100644 web/src/components/DonationAddress.astro create mode 100644 web/src/constants/announcementTypes.ts rename web/src/pages/{about.md => about.mdx} (97%) diff --git a/web/package-lock.json b/web/package-lock.json index 5b084e4..9901379 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -32,6 +32,7 @@ "lodash-es": "4.17.21", "mime-types": "3.0.1", "object-to-formdata": "4.5.1", + "qrcode": "1.5.4", "react": "19.1.0", "redis": "5.0.1", "schema-dts": "1.1.5", @@ -56,6 +57,7 @@ "@tailwindcss/typography": "0.5.16", "@types/eslint__js": "9.14.0", "@types/lodash-es": "4.17.12", + "@types/qrcode": "1.5.5", "@types/react": "19.1.4", "@types/seedrandom": "3.0.8", "@typescript-eslint/parser": "8.32.1", @@ -3160,6 +3162,16 @@ "pg-types": "^2.2.0" } }, + "node_modules/@types/qrcode": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@types/qrcode/-/qrcode-1.5.5.tgz", + "integrity": "sha512-CdfBi/e3Qk+3Z/fXYShipBT13OJ2fDO2Q2w5CIP5anLTLIndQG9z6P1cnm+8zCWSpm5dnxMFd/uREtb0EXuQzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/react": { "version": "19.1.4", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.4.tgz", @@ -5686,6 +5698,15 @@ } } }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/decode-named-character-reference": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.1.0.tgz", @@ -5907,6 +5928,12 @@ "node": ">=0.3.1" } }, + "node_modules/dijkstrajs": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.3.tgz", + "integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==", + "license": "MIT" + }, "node_modules/dlv": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", @@ -11110,6 +11137,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/package-manager-detector": { "version": "0.2.9", "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-0.2.9.tgz", @@ -11238,7 +11274,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -11349,6 +11384,15 @@ "dev": true, "license": "MIT" }, + "node_modules/pngjs": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz", + "integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==", + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/possible-typed-array-names": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", @@ -11724,6 +11768,206 @@ "node": ">=6" } }, + "node_modules/qrcode": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.4.tgz", + "integrity": "sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==", + "license": "MIT", + "dependencies": { + "dijkstrajs": "^1.0.1", + "pngjs": "^5.0.0", + "yargs": "^15.3.1" + }, + "bin": { + "qrcode": "bin/qrcode" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/qrcode/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/qrcode/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/qrcode/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/qrcode/node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/qrcode/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/qrcode/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/qrcode/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/qrcode/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/qrcode/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/qrcode/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/qrcode/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/qrcode/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/qrcode/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "license": "ISC" + }, + "node_modules/qrcode/node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "license": "MIT", + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/qrcode/node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "license": "ISC", + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -12168,6 +12412,12 @@ "node": ">=0.10.0" } }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "license": "ISC" + }, "node_modules/resolve": { "version": "1.22.10", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", @@ -12539,6 +12789,12 @@ "integrity": "sha512-rb+9B5YBIEzYcD6x2VKidaa+cqYBJQKnU4oe4E3ANwRRN56yk/ua1YCJT1n21NTS8w6CcOclAKNP3PhdCXKYtQ==", "license": "ISC" }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "license": "ISC" + }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", @@ -14550,6 +14806,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/which-module": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", + "license": "ISC" + }, "node_modules/which-pm-runs": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.1.0.tgz", diff --git a/web/package.json b/web/package.json index 9a5600d..180a113 100644 --- a/web/package.json +++ b/web/package.json @@ -26,8 +26,8 @@ "@astrojs/node": "9.2.1", "@astrojs/sitemap": "3.4.0", "@fontsource-variable/space-grotesk": "5.2.7", - "@fontsource/space-grotesk": "5.2.7", "@fontsource/inter": "5.2.5", + "@fontsource/space-grotesk": "5.2.7", "@prisma/client": "6.8.2", "@tailwindcss/vite": "4.1.7", "@types/mime-types": "2.1.4", @@ -44,6 +44,7 @@ "lodash-es": "4.17.21", "mime-types": "3.0.1", "object-to-formdata": "4.5.1", + "qrcode": "1.5.4", "react": "19.1.0", "redis": "5.0.1", "schema-dts": "1.1.5", @@ -68,6 +69,7 @@ "@tailwindcss/typography": "0.5.16", "@types/eslint__js": "9.14.0", "@types/lodash-es": "4.17.12", + "@types/qrcode": "1.5.5", "@types/react": "19.1.4", "@types/seedrandom": "3.0.8", "@typescript-eslint/parser": "8.32.1", diff --git a/web/src/components/AnnouncementBanner.astro b/web/src/components/AnnouncementBanner.astro index 1634be7..edfa25e 100644 --- a/web/src/components/AnnouncementBanner.astro +++ b/web/src/components/AnnouncementBanner.astro @@ -2,75 +2,50 @@ import { Icon } from 'astro-icon/components' import { Markdown } from 'astro-remote' -import type { AnnouncementType } from '@prisma/client' +import { getAnnouncementTypeInfo } from '../constants/announcementTypes' +import { cn } from '../lib/cn' -export type Announcement = { - id: number - title: string - content: string - type: AnnouncementType - startDate: Date - endDate: Date | null - isActive: boolean -} +import type { Prisma } from '@prisma/client' -export type Props = { - announcements: Announcement[] +type Props = { + announcements: + | Prisma.AnnouncementGetPayload<{ + select: { + id: true + title: true + content: true + type: true + startDate: true + endDate: true + isActive: true + } + }>[] + | null + | undefined } const { announcements } = Astro.props - -// Get icon and class based on announcement type -const getTypeInfo = (type: AnnouncementType) => { - switch (type) { - case 'INFO': - return { - icon: 'ri:information-line', - containerClass: 'bg-blue-900/40 border-blue-500/30', - titleClass: 'text-blue-400', - contentClass: 'text-blue-300', - } - case 'WARNING': - return { - icon: 'ri:alert-line', - containerClass: 'bg-yellow-900/40 border-yellow-500/30', - titleClass: 'text-yellow-400', - contentClass: 'text-yellow-300', - } - case 'ALERT': - return { - icon: 'ri:error-warning-line', - containerClass: 'bg-red-900/40 border-red-500/30', - titleClass: 'text-red-400', - contentClass: 'text-red-300', - } - default: - return { - icon: 'ri:information-line', - containerClass: 'bg-blue-900/40 border-blue-500/30', - titleClass: 'text-blue-400', - contentClass: 'text-blue-300', - } - } -} --- { - announcements.length > 0 && ( + !!announcements && announcements.length > 0 && (
{announcements.map((announcement) => { - const typeInfo = getTypeInfo(announcement.type) + const typeInfo = getAnnouncementTypeInfo(announcement.type) return (
- +
- + {announcement.title} - +
diff --git a/web/src/components/DonationAddress.astro b/web/src/components/DonationAddress.astro new file mode 100644 index 0000000..9bb1f8f --- /dev/null +++ b/web/src/components/DonationAddress.astro @@ -0,0 +1,60 @@ +--- +import { Icon } from 'astro-icon/components' +import QRCode from 'qrcode' + +import { cn } from '../lib/cn' + +type Props = { + cryptoName: string + cryptoIcon: string + address: string + className?: string +} + +const { cryptoName, cryptoIcon, address, className } = Astro.props + +function getAddressURI(address: string, cryptoName: string) { + if (cryptoName.toLowerCase() === 'monero') { + return `monero:${address}?tx_description=KYCnot.me%20Donation` + } + + if (cryptoName.toLowerCase() === 'bitcoin') { + return `bitcoin:${address}?label=KYCnot.me%20Donation` + } + + return address +} + +const qrCodeDataURL = await QRCode.toDataURL(getAddressURI(address, cryptoName), { + width: 128, + margin: 1, + color: { + dark: '#ffffff', + light: '#171721', + }, +}) +--- + +
+
+
+ + {cryptoName} +
+

+ 12 + ? `${address.substring(0, 6)}${address.substring(6, address.length - 6)}${address.substring(address.length - 6)}` + : `${address}`} + /> +

+
+ +
diff --git a/web/src/constants/announcementTypes.ts b/web/src/constants/announcementTypes.ts new file mode 100644 index 0000000..f8a4938 --- /dev/null +++ b/web/src/constants/announcementTypes.ts @@ -0,0 +1,65 @@ +import { makeHelpersForOptions } from '../lib/makeHelpersForOptions' +import { transformCase } from '../lib/strings' + +import type { AnnouncementType } from '@prisma/client' + +type AnnouncementTypeInfo = { + value: T + label: string + icon: string + classNames: { + container: string + title: string + content: string + } +} + +export const { + dataArray: announcementTypes, + dataObject: announcementTypesById, + getFn: getAnnouncementTypeInfo, +} = makeHelpersForOptions( + 'value', + (value): AnnouncementTypeInfo => ({ + value, + label: value ? transformCase(value.replaceAll('_', ' '), 'title') : String(value), + icon: 'ri:information-line', + classNames: { + container: 'bg-blue-900/40 border-blue-500/30', + title: 'text-blue-400', + content: 'text-blue-300', + }, + }), + [ + { + value: 'INFO', + label: 'Info', + icon: 'ri:information-line', + classNames: { + container: 'bg-blue-900/40 border-blue-500/30', + title: 'text-blue-400', + content: 'text-blue-300', + }, + }, + { + value: 'WARNING', + label: 'Warning', + icon: 'ri:alert-line', + classNames: { + container: 'bg-yellow-900/40 border-yellow-500/30', + title: 'text-yellow-400', + content: 'text-yellow-300', + }, + }, + { + value: 'ALERT', + label: 'Alert', + icon: 'ri:error-warning-line', + classNames: { + container: 'bg-red-900/40 border-red-500/30', + title: 'text-red-400', + content: 'text-red-300', + }, + }, + ] as const satisfies AnnouncementTypeInfo[] +) diff --git a/web/src/pages/about.md b/web/src/pages/about.mdx similarity index 97% rename from web/src/pages/about.md rename to web/src/pages/about.mdx index 27be689..875ccfa 100644 --- a/web/src/pages/about.md +++ b/web/src/pages/about.mdx @@ -7,6 +7,8 @@ description: 'Learn how KYCnot.me website works and about our mission to protect icon: 'ri:information-line' --- +import DonationAddress from '../components/DonationAddress.astro' + ## What is this page? KYCnot.me is a directory of trustworthy alternatives for buying, exchanging, trading, and using cryptocurrencies without having to disclose your identity, thus preserving your right to privacy. @@ -190,10 +192,13 @@ To **see comments waiting for moderation**, toggle the switch in the comments se ## Support the project -If you like this project, you can support it through these methods: +If you like this project, you can **support** it through these methods: -- Monero: - - `88V2Xi2mvcu3NdnHkVeZGyPtACg2w3iXZdUMJugUiPvFQHv5mVkih3o43ceVGz6cVs9uTBMt4MRMVW2xFgfGdh8DTCQ7vtp` + ## Contact @@ -202,8 +207,7 @@ You can contact via direct chat or via email. - [SimpleX Chat](https://simplex.chat/contact#/?v=2&smp=smp%3A%2F%2F0YuTwO05YJWS8rkjn9eLJDjQhFKvIYd8d4xG8X1blIU%3D%40smp8.simplex.im%2FcgKHYUYnpAIVoGb9lxb0qEMEpvYIvc1O%23%2F%3Fv%3D1-2%26dh%3DMCowBQYDK2VuAyEAIW_JSq8wOsLKG4Xv4O54uT2D_l8MJBYKQIFj1FjZpnU%253D%26srv%3Dbeccx4yfxxbvyhqypaavemqurytl6hozr47wfc7uuecacjqdvwpw2xid.onion) - If you use ProtonMail or Tutanota, you can have E2E encrypted communications with us directly. We also offer a [PGP Key](/pgp). Otherwise, we recommend reaching out via SimpleX chat for encrypted communications. - - [tuta.io](https://tuta.io) - - - [proton.me](https://proton.me) - + ## Disclaimer diff --git a/web/src/pages/admin/announcements/index.astro b/web/src/pages/admin/announcements/index.astro index e8cdf58..4b4dca4 100644 --- a/web/src/pages/admin/announcements/index.astro +++ b/web/src/pages/admin/announcements/index.astro @@ -4,6 +4,12 @@ import { actions, isInputError } from 'astro:actions' import { z } from 'astro:schema' import { adminAnnouncementActions } from '../../../actions/admin/announcement' +import Button from '../../../components/Button.astro' +import InputCardGroup from '../../../components/InputCardGroup.astro' +import InputSelect from '../../../components/InputSelect.astro' +import InputSubmitButton from '../../../components/InputSubmitButton.astro' +import InputText from '../../../components/InputText.astro' +import InputTextArea from '../../../components/InputTextArea.astro' import SortArrowIcon from '../../../components/SortArrowIcon.astro' import TimeFormatted from '../../../components/TimeFormatted.astro' import Tooltip from '../../../components/Tooltip.astro' @@ -99,6 +105,8 @@ const updateResult = Astro.getActionResult(adminAnnouncementActions.update) const deleteResult = Astro.getActionResult(adminAnnouncementActions.delete) const toggleResult = Astro.getActionResult(adminAnnouncementActions.toggleActive) +const createInputErrors = isInputError(createResult?.error) ? createResult.error.fields : {} + // Add success messages to banners Astro.locals.banners.addIfSuccess(createResult, 'Announcement created successfully!') Astro.locals.banners.addIfSuccess(updateResult, 'Announcement updated successfully!') @@ -221,100 +229,85 @@ if (toggleResult?.error) {

Create New Announcement

-
- - -
+ -
- - -
+
-
- - -
+ -
- - -
+ -
- - -
+
-
- - -
+
- - +
- - -
-
-

Edit Announcement

- -
- - - - -
-
- - -
- -
- - -
-
- -
-
- - -
- -
- - -
- -
- - -
-
- -
-
- - -
- -
- - - -
-
- -
-
- ( - - -
{announcement.title}
-
{announcement.content}
- - - - {announcement.type} - - - - - - - {announcement.endDate ? ( - - ) : ( - - )} - - - - {announcement.isActive ? 'Active' : 'Inactive'} - - - - - - -
- + + +
{announcement.title}
+
{announcement.content}
+ + + - -
+ {announcement.type} + + + + + + + {announcement.endDate ? ( + + ) : ( + + )} + + + + {announcement.isActive ? 'Active' : 'Inactive'} + + + + + + +
+ + + +
+ + + +
+ +
+ + +
+
+ + + + +

+ Edit: {announcement.title} +

- -
+ +
+ + + +
+ +
+ +
+ + +
+
- -
- - -
-
- - + + + )) } @@ -714,6 +687,9 @@ if (toggleResult?.error) { input[type='date'] { color-scheme: dark; } + input[type='datetime-local'] { + color-scheme: dark; + }