mirror of
https://github.com/spliit-app/spliit.git
synced 2026-02-15 03:56:13 +01:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d3b151e150 | ||
|
|
19c009f6b8 |
21
eslint.config.mjs
Normal file
21
eslint.config.mjs
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import nextVitals from 'eslint-config-next/core-web-vitals'
|
||||||
|
import { defineConfig, globalIgnores } from 'eslint/config'
|
||||||
|
|
||||||
|
const eslintConfig = defineConfig([
|
||||||
|
...nextVitals,
|
||||||
|
// Override default ignores of eslint-config-next.
|
||||||
|
globalIgnores([
|
||||||
|
// Default ignores of eslint-config-next:
|
||||||
|
'.next/**',
|
||||||
|
'out/**',
|
||||||
|
'build/**',
|
||||||
|
'next-env.d.ts',
|
||||||
|
]),
|
||||||
|
{
|
||||||
|
rules: {
|
||||||
|
'react-hooks/set-state-in-effect': 'off',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
export default eslintConfig
|
||||||
6389
package-lock.json
generated
6389
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
52
package.json
52
package.json
@@ -6,7 +6,7 @@
|
|||||||
"dev": "next dev",
|
"dev": "next dev",
|
||||||
"build": "next build",
|
"build": "next build",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"lint": "next lint",
|
"lint": "eslint .",
|
||||||
"check-types": "tsc --noEmit",
|
"check-types": "tsc --noEmit",
|
||||||
"check-formatting": "prettier -c src",
|
"check-formatting": "prettier -c src",
|
||||||
"prettier": "prettier -w src",
|
"prettier": "prettier -w src",
|
||||||
@@ -21,19 +21,19 @@
|
|||||||
"@hookform/resolvers": "^3.3.2",
|
"@hookform/resolvers": "^3.3.2",
|
||||||
"@json2csv/plainjs": "^7.0.6",
|
"@json2csv/plainjs": "^7.0.6",
|
||||||
"@prisma/client": "^6.18.0",
|
"@prisma/client": "^6.18.0",
|
||||||
"@radix-ui/react-checkbox": "^1.0.4",
|
"@radix-ui/react-checkbox": "^1.3.3",
|
||||||
"@radix-ui/react-collapsible": "^1.0.3",
|
"@radix-ui/react-collapsible": "^1.1.12",
|
||||||
"@radix-ui/react-dialog": "^1.0.5",
|
"@radix-ui/react-dialog": "^1.1.15",
|
||||||
"@radix-ui/react-dropdown-menu": "^2.0.6",
|
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
||||||
"@radix-ui/react-hover-card": "^1.0.7",
|
"@radix-ui/react-hover-card": "^1.1.15",
|
||||||
"@radix-ui/react-icons": "^1.3.0",
|
"@radix-ui/react-icons": "^1.3.2",
|
||||||
"@radix-ui/react-label": "^2.0.2",
|
"@radix-ui/react-label": "^2.1.8",
|
||||||
"@radix-ui/react-popover": "^1.0.7",
|
"@radix-ui/react-popover": "^1.1.15",
|
||||||
"@radix-ui/react-radio-group": "^1.1.3",
|
"@radix-ui/react-radio-group": "^1.3.8",
|
||||||
"@radix-ui/react-select": "^2.0.0",
|
"@radix-ui/react-select": "^2.2.6",
|
||||||
"@radix-ui/react-slot": "^1.0.2",
|
"@radix-ui/react-slot": "^1.2.4",
|
||||||
"@radix-ui/react-tabs": "^1.0.4",
|
"@radix-ui/react-tabs": "^1.1.13",
|
||||||
"@radix-ui/react-toast": "^1.1.5",
|
"@radix-ui/react-toast": "^1.2.15",
|
||||||
"@tailwindcss/typography": "^0.5.10",
|
"@tailwindcss/typography": "^0.5.10",
|
||||||
"@tanstack/react-query": "^5.59.15",
|
"@tanstack/react-query": "^5.59.15",
|
||||||
"@trpc/client": "^11.0.0-rc.586",
|
"@trpc/client": "^11.0.0-rc.586",
|
||||||
@@ -42,25 +42,25 @@
|
|||||||
"class-variance-authority": "^0.7.0",
|
"class-variance-authority": "^0.7.0",
|
||||||
"client-only": "^0.0.1",
|
"client-only": "^0.0.1",
|
||||||
"clsx": "^2.0.0",
|
"clsx": "^2.0.0",
|
||||||
"cmdk": "^0.2.0",
|
"cmdk": "^1.1.1",
|
||||||
"content-disposition": "^0.5.4",
|
"content-disposition": "^0.5.4",
|
||||||
"dayjs": "^1.11.10",
|
"dayjs": "^1.11.10",
|
||||||
"embla-carousel-react": "^8.0.0-rc21",
|
"embla-carousel-react": "^8.6.0",
|
||||||
"lucide-react": "^0.501.0",
|
"lucide-react": "^0.501.0",
|
||||||
"nanoid": "^5.0.4",
|
"nanoid": "^5.0.4",
|
||||||
"negotiator": "^0.6.3",
|
"negotiator": "^0.6.3",
|
||||||
"next": "^14.2.5",
|
"next": "^16.0.7",
|
||||||
"next-intl": "^3.17.2",
|
"next-intl": "^4.5.8",
|
||||||
"next-s3-upload": "^0.3.4",
|
"next-s3-upload": "^0.3.4",
|
||||||
"next-themes": "^0.2.1",
|
"next-themes": "^0.2.1",
|
||||||
"next13-progressbar": "^1.1.1",
|
"next13-progressbar": "^1.1.1",
|
||||||
"openai": "^4.25.0",
|
"openai": "^4.25.0",
|
||||||
"pg": "^8.11.3",
|
"pg": "^8.11.3",
|
||||||
"prisma": "^6.18.0",
|
"prisma": "^6.18.0",
|
||||||
"react": "^18.3.1",
|
"react": "^19.2.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^19.2.1",
|
||||||
"react-hook-form": "^7.47.0",
|
"react-hook-form": "^7.68.0",
|
||||||
"react-intersection-observer": "^9.8.0",
|
"react-intersection-observer": "^10.0.0",
|
||||||
"server-only": "^0.0.1",
|
"server-only": "^0.0.1",
|
||||||
"sharp": "^0.33.2",
|
"sharp": "^0.33.2",
|
||||||
"superjson": "^2.2.1",
|
"superjson": "^2.2.1",
|
||||||
@@ -70,13 +70,13 @@
|
|||||||
"ts-pattern": "^5.0.6",
|
"ts-pattern": "^5.0.6",
|
||||||
"use-debounce": "^10.0.4",
|
"use-debounce": "^10.0.4",
|
||||||
"uuid": "^9.0.1",
|
"uuid": "^9.0.1",
|
||||||
"vaul": "^0.8.0",
|
"vaul": "^1.1.2",
|
||||||
"zod": "^3.23.8"
|
"zod": "^3.23.8"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@testing-library/dom": "^10.4.0",
|
"@testing-library/dom": "^10.4.0",
|
||||||
"@testing-library/jest-dom": "^6.4.8",
|
"@testing-library/jest-dom": "^6.4.8",
|
||||||
"@testing-library/react": "^16.0.0",
|
"@testing-library/react": "^16.3.0",
|
||||||
"@total-typescript/ts-reset": "^0.5.1",
|
"@total-typescript/ts-reset": "^0.5.1",
|
||||||
"@types/content-disposition": "^0.5.8",
|
"@types/content-disposition": "^0.5.8",
|
||||||
"@types/jest": "^29.5.12",
|
"@types/jest": "^29.5.12",
|
||||||
@@ -89,8 +89,8 @@
|
|||||||
"autoprefixer": "^10",
|
"autoprefixer": "^10",
|
||||||
"currency-list": "^1.0.8",
|
"currency-list": "^1.0.8",
|
||||||
"dotenv": "^16.3.1",
|
"dotenv": "^16.3.1",
|
||||||
"eslint": "^8",
|
"eslint": "^9.39.1",
|
||||||
"eslint-config-next": "^14.1.0",
|
"eslint-config-next": "^16.0.7",
|
||||||
"jest": "^29.7.0",
|
"jest": "^29.7.0",
|
||||||
"jest-environment-jsdom": "^29.7.0",
|
"jest-environment-jsdom": "^29.7.0",
|
||||||
"postcss": "^8",
|
"postcss": "^8",
|
||||||
|
|||||||
@@ -6,6 +6,6 @@ else
|
|||||||
echo "postgres is not running, starting it"
|
echo "postgres is not running, starting it"
|
||||||
docker rm postgres --force
|
docker rm postgres --force
|
||||||
mkdir -p postgres-data
|
mkdir -p postgres-data
|
||||||
docker run --name spliit-db -d -p 5432:5432 -e POSTGRES_PASSWORD=1234 -v "/$(pwd)/postgres-data:/var/lib/postgresql/data" postgres
|
docker run --name spliit-db -d -p 5432:5432 -e POSTGRES_PASSWORD=1234 -v "/$(pwd)/postgres-data:/var/lib/postgresql" postgres
|
||||||
sleep 5 # Wait for postgres to start
|
sleep 5 # Wait for postgres to start
|
||||||
fi
|
fi
|
||||||
@@ -7,10 +7,11 @@ export const metadata: Metadata = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default async function EditExpensePage({
|
export default async function EditExpensePage({
|
||||||
params: { groupId, expenseId },
|
params,
|
||||||
}: {
|
}: {
|
||||||
params: { groupId: string; expenseId: string }
|
params: Promise<{ groupId: string; expenseId: string }>
|
||||||
}) {
|
}) {
|
||||||
|
const { groupId, expenseId } = await params
|
||||||
return (
|
return (
|
||||||
<EditExpenseForm
|
<EditExpenseForm
|
||||||
groupId={groupId}
|
groupId={groupId}
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ export function CategoryIcon({
|
|||||||
...props
|
...props
|
||||||
}: { category: Category | null } & LucideProps) {
|
}: { category: Category | null } & LucideProps) {
|
||||||
const Icon = getCategoryIcon(`${category?.grouping}/${category?.name}`)
|
const Icon = getCategoryIcon(`${category?.grouping}/${category?.name}`)
|
||||||
|
// eslint-disable-next-line react-hooks/static-components
|
||||||
return <Icon {...props} />
|
return <Icon {...props} />
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export async function extractExpenseInformationFromImage(imageUrl: string) {
|
|||||||
const categories = await getCategories()
|
const categories = await getCategories()
|
||||||
|
|
||||||
const body: ChatCompletionCreateParamsNonStreaming = {
|
const body: ChatCompletionCreateParamsNonStreaming = {
|
||||||
model: 'gpt-4-turbo',
|
model: 'gpt-5-nano',
|
||||||
messages: [
|
messages: [
|
||||||
{
|
{
|
||||||
role: 'user',
|
role: 'user',
|
||||||
|
|||||||
@@ -7,10 +7,11 @@ export const metadata: Metadata = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default async function ExpensePage({
|
export default async function ExpensePage({
|
||||||
params: { groupId },
|
params,
|
||||||
}: {
|
}: {
|
||||||
params: { groupId: string }
|
params: Promise<{ groupId: string }>
|
||||||
}) {
|
}) {
|
||||||
|
const { groupId } = await params
|
||||||
return (
|
return (
|
||||||
<CreateExpenseForm
|
<CreateExpenseForm
|
||||||
groupId={groupId}
|
groupId={groupId}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ import {
|
|||||||
SelectTrigger,
|
SelectTrigger,
|
||||||
SelectValue,
|
SelectValue,
|
||||||
} from '@/components/ui/select'
|
} from '@/components/ui/select'
|
||||||
import { Locale } from '@/i18n'
|
import { Locale } from '@/i18n/request'
|
||||||
import { randomId } from '@/lib/api'
|
import { randomId } from '@/lib/api'
|
||||||
import { defaultCurrencyList, getCurrency } from '@/lib/currency'
|
import { defaultCurrencyList, getCurrency } from '@/lib/currency'
|
||||||
import { RuntimeFeatureFlags } from '@/lib/featureFlags'
|
import { RuntimeFeatureFlags } from '@/lib/featureFlags'
|
||||||
|
|||||||
@@ -24,8 +24,9 @@ const prisma = new PrismaClient()
|
|||||||
|
|
||||||
export async function GET(
|
export async function GET(
|
||||||
req: Request,
|
req: Request,
|
||||||
{ params: { groupId } }: { params: { groupId: string } },
|
{ params }: { params: Promise<{ groupId: string }> },
|
||||||
) {
|
) {
|
||||||
|
const { groupId } = await params
|
||||||
const group = await prisma.group.findUnique({
|
const group = await prisma.group.findUnique({
|
||||||
where: { id: groupId },
|
where: { id: groupId },
|
||||||
select: {
|
select: {
|
||||||
|
|||||||
@@ -4,8 +4,9 @@ import { NextResponse } from 'next/server'
|
|||||||
|
|
||||||
export async function GET(
|
export async function GET(
|
||||||
req: Request,
|
req: Request,
|
||||||
{ params: { groupId } }: { params: { groupId: string } },
|
{ params }: { params: Promise<{ groupId: string }> },
|
||||||
) {
|
) {
|
||||||
|
const { groupId } = await params
|
||||||
const group = await prisma.group.findUnique({
|
const group = await prisma.group.findUnique({
|
||||||
where: { id: groupId },
|
where: { id: groupId },
|
||||||
select: {
|
select: {
|
||||||
|
|||||||
@@ -5,10 +5,11 @@ export const metadata: Metadata = {
|
|||||||
title: 'Group Information',
|
title: 'Group Information',
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function InformationPage({
|
export default async function InformationPage({
|
||||||
params: { groupId },
|
params,
|
||||||
}: {
|
}: {
|
||||||
params: { groupId: string }
|
params: Promise<{ groupId: string }>
|
||||||
}) {
|
}) {
|
||||||
|
const { groupId } = await params
|
||||||
return <GroupInformation groupId={groupId} />
|
return <GroupInformation groupId={groupId} />
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,14 +4,13 @@ import { PropsWithChildren } from 'react'
|
|||||||
import { GroupLayoutClient } from './layout.client'
|
import { GroupLayoutClient } from './layout.client'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
params: {
|
params: Promise<{
|
||||||
groupId: string
|
groupId: string
|
||||||
}
|
}>
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function generateMetadata({
|
export async function generateMetadata({ params }: Props): Promise<Metadata> {
|
||||||
params: { groupId },
|
const { groupId } = await params
|
||||||
}: Props): Promise<Metadata> {
|
|
||||||
const group = await cached.getGroup(groupId)
|
const group = await cached.getGroup(groupId)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -22,9 +21,10 @@ export async function generateMetadata({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function GroupLayout({
|
export default async function GroupLayout({
|
||||||
children,
|
children,
|
||||||
params: { groupId },
|
params,
|
||||||
}: PropsWithChildren<Props>) {
|
}: PropsWithChildren<Props>) {
|
||||||
|
const { groupId } = await params
|
||||||
return <GroupLayoutClient groupId={groupId}>{children}</GroupLayoutClient>
|
return <GroupLayoutClient groupId={groupId}>{children}</GroupLayoutClient>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import { redirect } from 'next/navigation'
|
import { redirect } from 'next/navigation'
|
||||||
|
|
||||||
export default async function GroupPage({
|
export default async function GroupPage({
|
||||||
params: { groupId },
|
params,
|
||||||
}: {
|
}: {
|
||||||
params: { groupId: string }
|
params: Promise<{ groupId: string }>
|
||||||
}) {
|
}) {
|
||||||
|
const { groupId } = await params
|
||||||
redirect(`/groups/${groupId}/expenses`)
|
redirect(`/groups/${groupId}/expenses`)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ export function ReimbursementList({
|
|||||||
<div className="flex flex-col gap-1 items-start sm:flex-row sm:items-baseline sm:gap-4">
|
<div className="flex flex-col gap-1 items-start sm:flex-row sm:items-baseline sm:gap-4">
|
||||||
<div>
|
<div>
|
||||||
{t.rich('owes', {
|
{t.rich('owes', {
|
||||||
from: getParticipant(reimbursement.from)?.name,
|
from: getParticipant(reimbursement.from)?.name ?? '',
|
||||||
to: getParticipant(reimbursement.to)?.name,
|
to: getParticipant(reimbursement.to)?.name ?? '',
|
||||||
strong: (chunks) => <strong>{chunks}</strong>,
|
strong: (chunks) => <strong>{chunks}</strong>,
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ import {
|
|||||||
Dialog,
|
Dialog,
|
||||||
DialogClose,
|
DialogClose,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
|
DialogDescription,
|
||||||
|
DialogTitle,
|
||||||
DialogTrigger,
|
DialogTrigger,
|
||||||
} from '@/components/ui/dialog'
|
} from '@/components/ui/dialog'
|
||||||
import { ToastAction } from '@/components/ui/toast'
|
import { ToastAction } from '@/components/ui/toast'
|
||||||
@@ -157,6 +159,8 @@ export function DocumentThumbnail({
|
|||||||
</Button>
|
</Button>
|
||||||
</DialogTrigger>
|
</DialogTrigger>
|
||||||
<DialogContent className="p-4 w-[100vw] max-w-[100vw] h-[100dvh] max-h-[100dvh] sm:max-w-[calc(100vw-32px)] sm:max-h-[calc(100dvh-32px)] [&>:last-child]:hidden">
|
<DialogContent className="p-4 w-[100vw] max-w-[100vw] h-[100dvh] max-h-[100dvh] sm:max-w-[calc(100vw-32px)] sm:max-h-[calc(100dvh-32px)] [&>:last-child]:hidden">
|
||||||
|
<DialogTitle className="sr-only">Document</DialogTitle>
|
||||||
|
<DialogDescription className="sr-only"></DialogDescription>
|
||||||
<div className="flex flex-col gap-4">
|
<div className="flex flex-col gap-4">
|
||||||
<div className="flex justify-end">
|
<div className="flex justify-end">
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ import {
|
|||||||
SelectTrigger,
|
SelectTrigger,
|
||||||
SelectValue,
|
SelectValue,
|
||||||
} from '@/components/ui/select'
|
} from '@/components/ui/select'
|
||||||
import { Locale } from '@/i18n'
|
import { Locale } from '@/i18n/request'
|
||||||
import { getGroup } from '@/lib/api'
|
import { getGroup } from '@/lib/api'
|
||||||
import { defaultCurrencyList, getCurrency } from '@/lib/currency'
|
import { defaultCurrencyList, getCurrency } from '@/lib/currency'
|
||||||
import { GroupFormValues, groupFormSchema } from '@/lib/schemas'
|
import { GroupFormValues, groupFormSchema } from '@/lib/schemas'
|
||||||
@@ -65,13 +65,14 @@ export function GroupForm({
|
|||||||
? {
|
? {
|
||||||
name: group.name,
|
name: group.name,
|
||||||
information: group.information ?? '',
|
information: group.information ?? '',
|
||||||
currency: group.currency,
|
currency: group.currency ?? '',
|
||||||
currencyCode: group.currencyCode,
|
currencyCode: group.currencyCode ?? '',
|
||||||
participants: group.participants,
|
participants: group.participants,
|
||||||
}
|
}
|
||||||
: {
|
: {
|
||||||
name: '',
|
name: '',
|
||||||
information: '',
|
information: '',
|
||||||
|
currency: '',
|
||||||
currencyCode: process.env.NEXT_PUBLIC_DEFAULT_CURRENCY_CODE || 'USD', // TODO: If NEXT_PUBLIC_DEFAULT_CURRENCY_CODE, is not set, determine the default currency code based on locale
|
currencyCode: process.env.NEXT_PUBLIC_DEFAULT_CURRENCY_CODE || 'USD', // TODO: If NEXT_PUBLIC_DEFAULT_CURRENCY_CODE, is not set, determine the default currency code based on locale
|
||||||
participants: [
|
participants: [
|
||||||
{ name: t('Participants.John') },
|
{ name: t('Participants.John') },
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import {
|
|||||||
DropdownMenuItem,
|
DropdownMenuItem,
|
||||||
DropdownMenuTrigger,
|
DropdownMenuTrigger,
|
||||||
} from '@/components/ui/dropdown-menu'
|
} from '@/components/ui/dropdown-menu'
|
||||||
import { Locale, localeLabels } from '@/i18n'
|
import { Locale, localeLabels } from '@/i18n/request'
|
||||||
import { setUserLocale } from '@/lib/locale'
|
import { setUserLocale } from '@/lib/locale'
|
||||||
import { useLocale } from 'next-intl'
|
import { useLocale } from 'next-intl'
|
||||||
|
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ const CommandItem = React.forwardRef<
|
|||||||
<CommandPrimitive.Item
|
<CommandPrimitive.Item
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none aria-selected:bg-accent aria-selected:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none aria-selected:bg-accent aria-selected:text-accent-foreground data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import deepmerge from 'deepmerge'
|
import deepmerge from 'deepmerge'
|
||||||
import { getRequestConfig } from 'next-intl/server'
|
import { getRequestConfig } from 'next-intl/server'
|
||||||
import { getUserLocale } from './lib/locale'
|
import { getUserLocale } from '../lib/locale'
|
||||||
|
|
||||||
export const localeLabels = {
|
export const localeLabels = {
|
||||||
id: 'Bahasa Indonesia',
|
id: 'Bahasa Indonesia',
|
||||||
@@ -37,14 +37,14 @@ export const defaultLocale: Locale = 'en-US'
|
|||||||
|
|
||||||
export default getRequestConfig(async () => {
|
export default getRequestConfig(async () => {
|
||||||
const locale = await getUserLocale()
|
const locale = await getUserLocale()
|
||||||
const localeMessages = (await import(`../messages/${locale}.json`)).default
|
const localeMessages = (await import(`../../messages/${locale}.json`)).default
|
||||||
|
|
||||||
let messages: any
|
let messages: any
|
||||||
if (locale === defaultLocale) {
|
if (locale === defaultLocale) {
|
||||||
messages = localeMessages
|
messages = localeMessages
|
||||||
} else {
|
} else {
|
||||||
messages = deepmerge(
|
messages = deepmerge(
|
||||||
(await import(`../messages/${defaultLocale}.json`)).default,
|
(await import(`../../messages/${defaultLocale}.json`)).default,
|
||||||
localeMessages,
|
localeMessages,
|
||||||
) as any
|
) as any
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Locale } from '@/i18n'
|
import { Locale } from '@/i18n/request'
|
||||||
import currencyList from './currency-data.json'
|
import currencyList from './currency-data.json'
|
||||||
|
|
||||||
export type Currency = {
|
export type Currency = {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
'use server'
|
'use server'
|
||||||
|
|
||||||
import { Locale, Locales, defaultLocale, locales } from '@/i18n'
|
import { Locale, Locales, defaultLocale, locales } from '@/i18n/request'
|
||||||
import { match } from '@formatjs/intl-localematcher'
|
import { match } from '@formatjs/intl-localematcher'
|
||||||
import Negotiator from 'negotiator'
|
import Negotiator from 'negotiator'
|
||||||
import { cookies, headers } from 'next/headers'
|
import { cookies, headers } from 'next/headers'
|
||||||
@@ -27,17 +27,17 @@ export async function getUserLocale() {
|
|||||||
let locale
|
let locale
|
||||||
|
|
||||||
// Prio 1: use existing cookie
|
// Prio 1: use existing cookie
|
||||||
locale = cookies().get(COOKIE_NAME)?.value
|
locale = (await cookies()).get(COOKIE_NAME)?.value
|
||||||
|
|
||||||
// Prio 2: use `accept-language` header
|
// Prio 2: use `accept-language` header
|
||||||
// Prio 3: use default locale
|
// Prio 3: use default locale
|
||||||
if (!locale) {
|
if (!locale) {
|
||||||
locale = getAcceptLanguageLocale(headers(), locales)
|
locale = getAcceptLanguageLocale(await headers(), locales)
|
||||||
}
|
}
|
||||||
|
|
||||||
return locale
|
return locale
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function setUserLocale(locale: Locale) {
|
export async function setUserLocale(locale: Locale) {
|
||||||
cookies().set(COOKIE_NAME, locale)
|
;(await cookies()).set(COOKIE_NAME, locale)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
import { Locale, locales } from '@/i18n'
|
import { Locale, locales } from '@/i18n/request'
|
||||||
import {
|
import {
|
||||||
Currency,
|
Currency,
|
||||||
supportedCurrencyCodeType,
|
supportedCurrencyCodeType,
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "es5",
|
"target": "es5",
|
||||||
"lib": ["dom", "dom.iterable", "esnext"],
|
"lib": [
|
||||||
|
"dom",
|
||||||
|
"dom.iterable",
|
||||||
|
"esnext"
|
||||||
|
],
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
@@ -11,7 +15,7 @@
|
|||||||
"moduleResolution": "bundler",
|
"moduleResolution": "bundler",
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
"jsx": "preserve",
|
"jsx": "react-jsx",
|
||||||
"incremental": true,
|
"incremental": true,
|
||||||
"plugins": [
|
"plugins": [
|
||||||
{
|
{
|
||||||
@@ -19,13 +23,26 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"paths": {
|
"paths": {
|
||||||
"@/*": ["./src/*"]
|
"@/*": [
|
||||||
|
"./src/*"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
"include": [
|
||||||
"exclude": ["node_modules"],
|
"next-env.d.ts",
|
||||||
|
"**/*.ts",
|
||||||
|
"**/*.tsx",
|
||||||
|
".next/types/**/*.ts",
|
||||||
|
".next/dev/types/**/*.ts"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"node_modules"
|
||||||
|
],
|
||||||
"ts-node": {
|
"ts-node": {
|
||||||
"require": ["tsconfig-paths/register", "dotenv/config"],
|
"require": [
|
||||||
|
"tsconfig-paths/register",
|
||||||
|
"dotenv/config"
|
||||||
|
],
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"isolatedModules": false,
|
"isolatedModules": false,
|
||||||
"moduleResolution": "nodenext",
|
"moduleResolution": "nodenext",
|
||||||
|
|||||||
Reference in New Issue
Block a user