feat: add Revolut payment link support alongside IBAN
- Add NoteBox component for displaying warning messages with icon - Add Revolut profile name field to user settings schema - Update UserSettingsForm to support payment instruction selection (disabled/IBAN/Revolut) - Add Croatian and English translations for new payment options - Reserve fields for future per-instruction enable/disable functionality 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -28,8 +28,18 @@ export interface UserSettings {
|
||||
ownerIBAN?: string | null;
|
||||
/** currency (ISO 4217) */
|
||||
currency?: string | null;
|
||||
/** owner Revolut payment link */
|
||||
ownerRevolutProfileName?: string | null;
|
||||
/** whether to show 2D code in monthly statement */
|
||||
show2dCodeInMonthlyStatement?: boolean | null;
|
||||
/** whether to show payment instructions in monthly statement */
|
||||
showPaymentInstructionsInMonthlyStatement?: "disabled" | "iban" | "revolut" | null;
|
||||
|
||||
// /** whether enableshow IBAN payment instructions in monthly statement */
|
||||
// enableIbanPaymentInstructionsInMonthlyStatement?: boolean | null;
|
||||
// /** whether to enable Revolut payment instructions in monthly statement */
|
||||
// enableRevolutPaymentInstructionsInMonthlyStatement?: boolean | null;
|
||||
|
||||
};
|
||||
|
||||
/** bill object in the form returned by MongoDB */
|
||||
|
||||
7
app/ui/NoteBox.tsx
Normal file
7
app/ui/NoteBox.tsx
Normal file
@@ -0,0 +1,7 @@
|
||||
import { FC, ReactNode } from "react";
|
||||
|
||||
export const NoteBox: FC<{ children: ReactNode, className?: string }> = ({ children, className }) =>
|
||||
<div className={`alert max-w-md flex flex-row items-start gap-[.8rem] ml-1 ${className}`}>
|
||||
<span className="w-6 h-6 text-xl">⚠️</span>
|
||||
<span className="text-left">{children}</span>
|
||||
</div>
|
||||
@@ -9,6 +9,7 @@ import Link from "next/link";
|
||||
import SettingsIcon from "@mui/icons-material/Settings";
|
||||
import { formatIban } from "../lib/formatStrings";
|
||||
import { InfoBox } from "./InfoBox";
|
||||
import { NoteBox } from "./NoteBox";
|
||||
|
||||
export type UserSettingsFormProps = {
|
||||
userSettings: UserSettings | null;
|
||||
@@ -32,21 +33,16 @@ const FormFields: FC<FormFieldsProps> = ({ userSettings, errors, message }) => {
|
||||
ownerTown: userSettings?.ownerTown ?? "",
|
||||
ownerIBAN: formatIban(userSettings?.ownerIBAN) ?? "",
|
||||
currency: userSettings?.currency ?? "EUR",
|
||||
ownerRevolutProfileName: userSettings?.ownerRevolutProfileName ?? "",
|
||||
showPaymentInstructions: userSettings?.showPaymentInstructionsInMonthlyStatement ?? "disabled",
|
||||
});
|
||||
|
||||
// https://revolut.me/aderezic?currency=EUR&amount=70000
|
||||
|
||||
const handleInputChange = (field: keyof typeof formValues, value: string) => {
|
||||
setFormValues(prev => ({ ...prev, [field]: value }));
|
||||
};
|
||||
|
||||
// Check if any required field is missing (clean IBAN of spaces for validation)
|
||||
const cleanedOwnerIBAN = formValues.ownerIBAN.replace(/\s/g, '');
|
||||
const hasMissingData = !formValues.ownerName || !formValues.ownerStreet || !formValues.ownerTown || !cleanedOwnerIBAN || !formValues.currency;
|
||||
|
||||
// Track whether to generate 2D code for tenant (use persisted value from database)
|
||||
const [show2dCodeInMonthlyStatement, setShow2dCodeInMonthlyStatement] = useState(
|
||||
userSettings?.show2dCodeInMonthlyStatement ?? false
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<fieldset className="fieldset bg-base-200 border-base-300 rounded-box w-xs border p-4 pt-1 pb-2 mt-4">
|
||||
@@ -60,7 +56,7 @@ const FormFields: FC<FormFieldsProps> = ({ userSettings, errors, message }) => {
|
||||
id="currency"
|
||||
name="currency"
|
||||
className="select select-bordered w-full"
|
||||
defaultValue={userSettings?.currency ?? "EUR"}
|
||||
defaultValue={formValues.currency}
|
||||
onChange={(e) => handleInputChange("currency", e.target.value)}
|
||||
disabled={pending}
|
||||
>
|
||||
@@ -111,25 +107,28 @@ const FormFields: FC<FormFieldsProps> = ({ userSettings, errors, message }) => {
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset className="fieldset bg-base-200 border-base-300 rounded-box w-xs border p-4 pb-2 mt-4">
|
||||
<legend className="fieldset-legend font-semibold uppercase">{t("tenant-2d-code-legend")}</legend>
|
||||
<legend className="fieldset-legend font-semibold uppercase">{t("tenant-payment-instructions--legend")}</legend>
|
||||
|
||||
<InfoBox className="p-1 mb-1">{t("info-box-message")}</InfoBox>
|
||||
|
||||
<fieldset className="fieldset">
|
||||
<label className="label cursor-pointer justify-start gap-3">
|
||||
<input
|
||||
type="checkbox"
|
||||
name="generateTenantCode"
|
||||
className="toggle toggle-primary"
|
||||
checked={show2dCodeInMonthlyStatement}
|
||||
onChange={(e) => setShow2dCodeInMonthlyStatement(e.target.checked)}
|
||||
/>
|
||||
<legend className="fieldset-legend">{t("tenant-2d-code-toggle-label")}</legend>
|
||||
</label>
|
||||
<fieldset className="form-control w-full">
|
||||
<select
|
||||
id="showPaymentInstructions"
|
||||
name="showPaymentInstructions"
|
||||
className="select select-bordered w-full"
|
||||
defaultValue={formValues.showPaymentInstructions}
|
||||
onChange={(e) => handleInputChange("showPaymentInstructions", e.target.value)}
|
||||
disabled={pending}
|
||||
>
|
||||
<option value="disabled">{t("tenant-payment-instructions--show-no-instructions")}</option>
|
||||
<option value="iban">{t("tenant-payment-instructions--show-iban-instructions")}</option>
|
||||
<option value="revolut">{t("tenant-payment-instructions--show-revolut-instructions")}</option>
|
||||
|
||||
</select>
|
||||
</fieldset>
|
||||
|
||||
{show2dCodeInMonthlyStatement && (
|
||||
{formValues.showPaymentInstructions === "iban" && (
|
||||
<>
|
||||
<div className="divider mt-6 mb-2 font-bold uppercase">Informacije za uplatu</div>
|
||||
<div className="form-control w-full">
|
||||
<label className="label">
|
||||
<span className="label-text">{t("owner-name-label")}</span>
|
||||
@@ -141,7 +140,7 @@ const FormFields: FC<FormFieldsProps> = ({ userSettings, errors, message }) => {
|
||||
maxLength={25}
|
||||
placeholder={t("owner-name-placeholder")}
|
||||
className="input input-bordered w-full placeholder:text-gray-600"
|
||||
defaultValue={userSettings?.ownerName ?? ""}
|
||||
defaultValue={formValues.ownerName}
|
||||
onChange={(e) => handleInputChange("ownerName", e.target.value)}
|
||||
disabled={pending}
|
||||
/>
|
||||
@@ -166,7 +165,7 @@ const FormFields: FC<FormFieldsProps> = ({ userSettings, errors, message }) => {
|
||||
maxLength={25}
|
||||
placeholder={t("owner-street-placeholder")}
|
||||
className="input input-bordered w-full placeholder:text-gray-600"
|
||||
defaultValue={userSettings?.ownerStreet ?? ""}
|
||||
defaultValue={formValues.ownerStreet}
|
||||
onChange={(e) => handleInputChange("ownerStreet", e.target.value)}
|
||||
disabled={pending}
|
||||
/>
|
||||
@@ -191,7 +190,7 @@ const FormFields: FC<FormFieldsProps> = ({ userSettings, errors, message }) => {
|
||||
maxLength={27}
|
||||
placeholder={t("owner-town-placeholder")}
|
||||
className="input input-bordered w-full placeholder:text-gray-600"
|
||||
defaultValue={userSettings?.ownerTown ?? ""}
|
||||
defaultValue={formValues.ownerTown}
|
||||
onChange={(e) => handleInputChange("ownerTown", e.target.value)}
|
||||
disabled={pending}
|
||||
/>
|
||||
@@ -215,7 +214,7 @@ const FormFields: FC<FormFieldsProps> = ({ userSettings, errors, message }) => {
|
||||
type="text"
|
||||
placeholder={t("owner-iban-placeholder")}
|
||||
className="input input-bordered w-full placeholder:text-gray-600"
|
||||
defaultValue={formatIban(userSettings?.ownerIBAN)}
|
||||
defaultValue={formValues.ownerIBAN}
|
||||
onChange={(e) => handleInputChange("ownerIBAN", e.target.value)}
|
||||
disabled={pending}
|
||||
/>
|
||||
@@ -229,9 +228,39 @@ const FormFields: FC<FormFieldsProps> = ({ userSettings, errors, message }) => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<InfoBox className="p-1 mt-1">{t("additional-notes")}</InfoBox>
|
||||
<NoteBox className="p-1 mt-1">{t("payment-additional-notes")}</NoteBox>
|
||||
</>
|
||||
)}
|
||||
{formValues.showPaymentInstructions === "revolut" && (
|
||||
<>
|
||||
<div className="divider mt-6 mb-2 font-bold uppercase">Informacije za uplatu</div>
|
||||
<div className="form-control w-full">
|
||||
<label className="label">
|
||||
<span className="label-text">{t("owner-revolut-link-label")}</span>
|
||||
</label>
|
||||
<input
|
||||
id="ownerRevolutProfileName"
|
||||
name="ownerRevolutProfileName"
|
||||
type="text"
|
||||
maxLength={25}
|
||||
placeholder={t("owner-revolut-link-placeholder")}
|
||||
className="input input-bordered w-full placeholder:text-gray-600"
|
||||
defaultValue={formValues.ownerRevolutProfileName}
|
||||
onChange={(e) => handleInputChange("ownerRevolutProfileName", e.target.value)}
|
||||
disabled={pending}
|
||||
/>
|
||||
<div id="ownerRevolutProfileName-error" aria-live="polite" aria-atomic="true">
|
||||
{errors?.ownerRevolutProfileName &&
|
||||
errors.ownerRevolutProfileName.map((error: string) => (
|
||||
<p className="mt-2 text-sm text-red-500" key={error}>
|
||||
{error}
|
||||
</p>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<NoteBox className="p-1 mt-1">{t("payment-additional-notes")}</NoteBox>
|
||||
</>
|
||||
)}
|
||||
</fieldset>
|
||||
|
||||
<div id="general-error" aria-live="polite" aria-atomic="true">
|
||||
|
||||
@@ -194,6 +194,13 @@
|
||||
"info-box-message": "By activating this option, a 2D barcode will be included in the monthly statement sent to the tenant, allowing them to make a direct payment to your bank account.",
|
||||
"tenant-2d-code-legend": "TENANT 2D CODE",
|
||||
"tenant-2d-code-toggle-label": "include 2D code in monthly statements",
|
||||
|
||||
"tenant-payment-instructions--legend": "Payment Instructions",
|
||||
"tenant-payment-instructions--info": "If you enable this option, the monthly statement sent to the tenant will include payment instructions and a 2D barcode, allowing them to make a direct payment to your bank account.",
|
||||
"tenant-payment-instructions--show-no-instructions": "🚫 - do not show payment instructions",
|
||||
"tenant-payment-instructions--show-iban-instructions": "🏦 - show payment instructions for IBAN",
|
||||
"tenant-payment-instructions--show-revolut-instructions": "🆁 - show payment instructions for Revolut",
|
||||
|
||||
"owner-name-label": "Your First and Last Name",
|
||||
"owner-name-placeholder": "enter your first and last name",
|
||||
"owner-street-label": "Your Street and House Number",
|
||||
@@ -201,7 +208,12 @@
|
||||
"owner-town-label": "Your Postal Code and Town",
|
||||
"owner-town-placeholder": "enter your postal code and town",
|
||||
"owner-iban-label": "IBAN",
|
||||
"owner-iban-placeholder": "enter your IBAN",
|
||||
"owner-iban-placeholder": "enter your IBAN for receiving payments",
|
||||
|
||||
"owner-revolut-profile-label": "Revolut profile name",
|
||||
"owner-revolut-profile-placeholder": "enter your Revolut profile name for receiving payments",
|
||||
"owner-revolut-profile-tooltip": "You can find your Revolut profile name in the Revolut app under your user profile. It is displayed below your name and starts with the '@' symbol (e.g., '@john123').",
|
||||
|
||||
"general-settings-legend": "General Settings",
|
||||
"currency-label": "Currency",
|
||||
"save-button": "Save",
|
||||
@@ -215,6 +227,6 @@
|
||||
"currency-required": "Currency is mandatory",
|
||||
"validation-failed": "Validation failed. Please check the form and try again."
|
||||
},
|
||||
"additional-notes": "Note: For the 2D code to be displayed, you must enter both the tenant's first and last names in the settings of each property for which you want to use this functionality."
|
||||
"payment-additional-notes": "IMPORTANT: For the payment instructions to be displayed to the tenant, you must also enable this option in the property's settings."
|
||||
}
|
||||
}
|
||||
@@ -190,9 +190,12 @@
|
||||
},
|
||||
"user-settings-form": {
|
||||
"title": "Korisničke postavke",
|
||||
"info-box-message": "Ako uključite ovu opciji na mjesečnom obračunu koji se šalje podstanaru biti će prikazan 2D bar kod, putem kojeg će moći izvršiti izravnu uplatu na vaš bankovni račun.",
|
||||
"tenant-2d-code-legend": "2D BARKOD ZA PODSTANARA",
|
||||
"tenant-2d-code-toggle-label": "prikazuj 2D barkod u mjesečnom obračunu",
|
||||
"info-box-message": "Ako uključite ovu opciju na mjesečnom obračunu koji se šalje podstanaru biti će prikazane upute za uplatu i 2D bar kod, putem kojeg će moći izvršiti izravnu uplatu na vaš bankovni račun.",
|
||||
"tenant-payment-instructions--legend": "Upute za uplatu",
|
||||
"tenant-payment-instructions--info": "Ako uključite ovu opciju na mjesečnom obračunu koji se šalje podstanaru biti će prikazane upute za uplatu i 2D bar kod, putem kojeg će moći izvršiti izravnu uplatu na vaš bankovni račun.",
|
||||
"tenant-payment-instructions--show-no-instructions": "🚫 - Ne prikazivati upute za uplatu",
|
||||
"tenant-payment-instructions--show-iban-instructions": "🏦 - Prikazuj upute za uplatu na IBAN",
|
||||
"tenant-payment-instructions--show-revolut-instructions": "🆁 - Prikazuj upute za uplatu na Revolut",
|
||||
"owner-name-label": "Vaše ime i prezime",
|
||||
"owner-name-placeholder": "unesite svoje ime i prezime",
|
||||
"owner-street-label": "Ulica i kućni broj",
|
||||
@@ -200,7 +203,11 @@
|
||||
"owner-town-label": "Poštanski broj i Grad",
|
||||
"owner-town-placeholder": "unesite poštanski broj i grad",
|
||||
"owner-iban-label": "IBAN",
|
||||
"owner-iban-placeholder": "unesite svoj IBAN",
|
||||
"owner-iban-placeholder": "IBAN putem kojeg ćete primate uplate",
|
||||
"owner-revolut-profile-label": "Naziv vašeg Revolut profila",
|
||||
"owner-revolut-profile-placeholder": "profil putem kojeg ćete primati uplate",
|
||||
"owner-revolut-profile-tooltip": "Naziv vašeg Revolute profila možete pronaći u aplikaciji Revolut u korisničkom profilu. Prikazan je ispod vašeg imena i prezimena - počinje sa znakom '@' (npr: '@ivan123').",
|
||||
|
||||
"general-settings-legend": "Opće postavke",
|
||||
"currency-label": "Valuta",
|
||||
"save-button": "Spremi",
|
||||
@@ -214,6 +221,6 @@
|
||||
"currency-required": "Valuta je obavezna",
|
||||
"validation-failed": "Validacija nije uspjela. Molimo provjerite formu i pokušajte ponovno."
|
||||
},
|
||||
"additional-notes": "Napomena: da bi 2D koda bio prikazan, morate unijeti i ime i prezime podstanara u postavkama svake nekretnine za koju želite koristiti ovu funkcionalnost."
|
||||
"payment-additional-notes": "VAŽNO: da bi upute za uplatu bile prikazane podstanaru, morate tu ovu opciju uključiti i u postavkama pripadajuće nekretnine."
|
||||
}
|
||||
}
|
||||
21
package-lock.json
generated
21
package-lock.json
generated
@@ -147,7 +147,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.9.tgz",
|
||||
"integrity": "sha512-5q0175NOjddqpvvzU+kDiSOAk4PfdO6FvwCWoQ6RO7rTzEe8vlo+4HVfcnAREhD4npMs0e9uZypjTwzZPCf/cw==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@ampproject/remapping": "^2.2.0",
|
||||
"@babel/code-frame": "^7.23.5",
|
||||
@@ -501,7 +500,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz",
|
||||
"integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.18.3",
|
||||
"@emotion/babel-plugin": "^11.13.5",
|
||||
@@ -545,7 +543,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.14.1.tgz",
|
||||
"integrity": "sha512-qEEJt42DuToa3gurlH4Qqc1kVpNq8wO8cJtDzU46TjlzWjDlsVyevtYCRijVq3SrHsROS+gVQ8Fnea108GnKzw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.18.3",
|
||||
"@emotion/babel-plugin": "^11.13.5",
|
||||
@@ -1072,7 +1069,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@mui/material/-/material-7.3.5.tgz",
|
||||
"integrity": "sha512-8VVxFmp1GIm9PpmnQoCoYo0UWHoOrdA57tDL62vkpzEgvb/d71Wsbv4FRg7r1Gyx7PuSo0tflH34cdl/NvfHNQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.28.4",
|
||||
"@mui/core-downloads-tracker": "^7.3.5",
|
||||
@@ -1473,7 +1469,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-14.1.0.tgz",
|
||||
"integrity": "sha512-x4FavbNEeXx/baD/zC/SdrvkjSby8nBn8KcCREqk6UuwvwoAPZmaV8TFCAuo/cpovBRTIY67mHhe86MQQm/68Q==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"glob": "10.3.10"
|
||||
}
|
||||
@@ -1804,7 +1799,6 @@
|
||||
"version": "18.2.21",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.21.tgz",
|
||||
"integrity": "sha512-neFKG/sBAwGxHgXiIxnbm3/AAVQ/cMRS93hvBpg8xYRbeQSPVABp9U2bRnPf0iI4+Ucdv3plSxKK+3CW2ENJxA==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/prop-types": "*",
|
||||
"@types/scheduler": "*",
|
||||
@@ -1926,7 +1920,6 @@
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz",
|
||||
"integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "6.21.0",
|
||||
"@typescript-eslint/types": "6.21.0",
|
||||
@@ -2226,7 +2219,6 @@
|
||||
"version": "0.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@zxing/library/-/library-0.20.0.tgz",
|
||||
"integrity": "sha512-6Ev6rcqVjMakZFIDvbUf0dtpPGeZMTfyxYg4HkVWioWeN7cRcnUWT3bU6sdohc82O1nPXcjq6WiGfXX2Pnit6A==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"ts-custom-error": "^3.2.1"
|
||||
},
|
||||
@@ -2253,7 +2245,6 @@
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz",
|
||||
"integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
@@ -2673,7 +2664,6 @@
|
||||
"url": "https://github.com/sponsors/ai"
|
||||
}
|
||||
],
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"caniuse-lite": "^1.0.30001587",
|
||||
"electron-to-chromium": "^1.4.668",
|
||||
@@ -3352,7 +3342,6 @@
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz",
|
||||
"integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.2.0",
|
||||
"@eslint-community/regexpp": "^4.6.1",
|
||||
@@ -3548,7 +3537,6 @@
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz",
|
||||
"integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"array-includes": "^3.1.7",
|
||||
"array.prototype.findlastindex": "^1.2.3",
|
||||
@@ -5988,7 +5976,6 @@
|
||||
"resolved": "https://registry.npmjs.org/next/-/next-14.2.33.tgz",
|
||||
"integrity": "sha512-GiKHLsD00t4ACm1p00VgrI0rUFAC9cRDGReKyERlM57aeEZkOQGcZTpIbsGn0b562FTPJWmYfKwplfO9EaT6ng==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@next/env": "14.2.33",
|
||||
"@swc/helpers": "0.5.5",
|
||||
@@ -6506,7 +6493,6 @@
|
||||
"version": "8.11.3",
|
||||
"resolved": "https://registry.npmjs.org/pg/-/pg-8.11.3.tgz",
|
||||
"integrity": "sha512-+9iuvG8QfaaUrrph+kpF24cXkH1YOOUeArRNYIxq1viYHZagBxrTno7cecY1Fa44tJeZvaoG+Djpkc3JwehN5g==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"buffer-writer": "2.0.0",
|
||||
"packet-reader": "1.0.0",
|
||||
@@ -6708,7 +6694,6 @@
|
||||
"url": "https://github.com/sponsors/ai"
|
||||
}
|
||||
],
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"nanoid": "^3.3.6",
|
||||
"picocolors": "^1.0.0",
|
||||
@@ -6894,7 +6879,6 @@
|
||||
"resolved": "https://registry.npmjs.org/preact/-/preact-10.24.3.tgz",
|
||||
"integrity": "sha512-Z2dPnBnMUfyQfSQ+GBdsGa16hz35YmLmtTLhM169uW944hYL6xzTYkJjC07j+Wosz733pMWx0fgON3JNw1jJQA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/preact"
|
||||
@@ -6923,7 +6907,6 @@
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz",
|
||||
"integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==",
|
||||
"dev": true,
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"prettier": "bin/prettier.cjs"
|
||||
},
|
||||
@@ -7065,7 +7048,6 @@
|
||||
"version": "18.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
|
||||
"integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0"
|
||||
},
|
||||
@@ -7077,7 +7059,6 @@
|
||||
"version": "18.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
|
||||
"integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"scheduler": "^0.23.0"
|
||||
@@ -8002,7 +7983,6 @@
|
||||
"version": "3.4.1",
|
||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.1.tgz",
|
||||
"integrity": "sha512-qAYmXRfk3ENzuPBakNK0SRrUDipP8NQnEY6772uDhflcQz5EhRdD7JNZxyrFHVQNCwULPBn6FNPp9brpO7ctcA==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@alloc/quick-lru": "^5.2.0",
|
||||
"arg": "^5.0.2",
|
||||
@@ -8308,7 +8288,6 @@
|
||||
"version": "5.2.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz",
|
||||
"integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
|
||||
Reference in New Issue
Block a user