timezone via cookies
This commit is contained in:
parent
530425a82c
commit
c03811e860
@ -1,6 +1,6 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import { useEffect, useState, useCallback, useMemo } from 'react'
|
import { useEffect, useState, useCallback } from 'react'
|
||||||
import { useSession } from 'next-auth/react'
|
import { useSession } from 'next-auth/react'
|
||||||
import { useRouter, usePathname } from '@/i18n/navigation'
|
import { useRouter, usePathname } from '@/i18n/navigation'
|
||||||
import { useTranslations, useLocale } from 'next-intl'
|
import { useTranslations, useLocale } from 'next-intl'
|
||||||
@ -99,36 +99,19 @@ function dateKeyInTZ(date: Date | string, timeZone: string): string {
|
|||||||
return `${p.year}-${pad(p.month)}-${pad(p.day)}`; // YYYY-MM-DD
|
return `${p.year}-${pad(p.month)}-${pad(p.day)}`; // YYYY-MM-DD
|
||||||
}
|
}
|
||||||
|
|
||||||
function readCookieClient(name: string): string | undefined {
|
|
||||||
if (typeof document === 'undefined') return undefined
|
|
||||||
const m = document.cookie.match(new RegExp('(?:^|; )' + name + '=([^;]*)'))
|
|
||||||
return m ? decodeURIComponent(m[1]) : undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
function isValidIanaTzClient(tz?: string): tz is string {
|
|
||||||
if (!tz) return false
|
|
||||||
try { new Intl.DateTimeFormat('en-US', { timeZone: tz }).format(0); return true } catch { return false }
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function CommunityMatchList({ matchType }: Props) {
|
export default function CommunityMatchList({ matchType }: Props) {
|
||||||
const { data: session } = useSession()
|
const { data: session } = useSession()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const pathname = usePathname()
|
const pathname = usePathname()
|
||||||
const locale = useLocale()
|
const locale = useLocale()
|
||||||
const [userTZ, setUserTZ] = useState<string>(() => {
|
const userTZ = getUserTimeZone(session?.user?.timeZone);
|
||||||
const fromCookie = readCookieClient('tz')
|
const weekdayFmt = new Intl.DateTimeFormat(
|
||||||
if (isValidIanaTzClient(fromCookie)) return fromCookie!
|
locale === 'de' ? 'de-DE' : 'en-GB',
|
||||||
if (session?.user?.timeZone && isValidIanaTzClient(session.user.timeZone)) return session.user.timeZone
|
{
|
||||||
return Intl.DateTimeFormat().resolvedOptions().timeZone || 'Europe/Berlin'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
console.log(userTZ);
|
|
||||||
const weekdayFmt = useMemo(() =>
|
|
||||||
new Intl.DateTimeFormat(locale === 'de' ? 'de-DE' : 'en-GB', {
|
|
||||||
weekday: 'long',
|
weekday: 'long',
|
||||||
timeZone: userTZ,
|
timeZone: userTZ,
|
||||||
}),
|
}
|
||||||
[locale, userTZ])
|
);
|
||||||
|
|
||||||
const tMatches = useTranslations('matches')
|
const tMatches = useTranslations('matches')
|
||||||
const tMapvote = useTranslations('mapvote')
|
const tMapvote = useTranslations('mapvote')
|
||||||
@ -162,24 +145,6 @@ export default function CommunityMatchList({ matchType }: Props) {
|
|||||||
|
|
||||||
const [now, setNow] = useState(() => Date.now())
|
const [now, setNow] = useState(() => Date.now())
|
||||||
|
|
||||||
// Beim Mount & Tab-Fokus Cookie neu einlesen
|
|
||||||
useEffect(() => {
|
|
||||||
const apply = () => {
|
|
||||||
const fromCookie = readCookieClient('tz')
|
|
||||||
if (isValidIanaTzClient(fromCookie)) {
|
|
||||||
setUserTZ(prev => (prev === fromCookie ? prev : fromCookie!))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
apply()
|
|
||||||
const onFocus = () => apply()
|
|
||||||
window.addEventListener('focus', onFocus)
|
|
||||||
document.addEventListener('visibilitychange', onFocus)
|
|
||||||
return () => {
|
|
||||||
window.removeEventListener('focus', onFocus)
|
|
||||||
document.removeEventListener('visibilitychange', onFocus)
|
|
||||||
}
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const id = setInterval(() => setNow(Date.now()), 1000)
|
const id = setInterval(() => setNow(Date.now()), 1000)
|
||||||
return () => clearInterval(id)
|
return () => clearInterval(id)
|
||||||
@ -639,4 +604,4 @@ function formatCountdown(ms: number) {
|
|||||||
const s = totalSec % 60
|
const s = totalSec % 60
|
||||||
const pad = (n:number)=>String(n).padStart(2,'0')
|
const pad = (n:number)=>String(n).padStart(2,'0')
|
||||||
return `${h}:${pad(m)}:${pad(s)}`
|
return `${h}:${pad(m)}:${pad(s)}`
|
||||||
}
|
}
|
||||||
@ -35,11 +35,11 @@ exports.Prisma = Prisma
|
|||||||
exports.$Enums = {}
|
exports.$Enums = {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prisma Client JS version: 6.16.2
|
* Prisma Client JS version: 6.16.1
|
||||||
* Query Engine version: 1c57fdcd7e44b29b9313256c76699e91c3ac3c43
|
* Query Engine version: 1c57fdcd7e44b29b9313256c76699e91c3ac3c43
|
||||||
*/
|
*/
|
||||||
Prisma.prismaVersion = {
|
Prisma.prismaVersion = {
|
||||||
client: "6.16.2",
|
client: "6.16.1",
|
||||||
engine: "1c57fdcd7e44b29b9313256c76699e91c3ac3c43"
|
engine: "1c57fdcd7e44b29b9313256c76699e91c3ac3c43"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -370,7 +370,7 @@ const config = {
|
|||||||
"value": "prisma-client-js"
|
"value": "prisma-client-js"
|
||||||
},
|
},
|
||||||
"output": {
|
"output": {
|
||||||
"value": "C:\\Users\\Rother\\fork\\ironie-nextjs\\src\\generated\\prisma",
|
"value": "C:\\Users\\Chris\\fork\\ironie-nextjs\\src\\generated\\prisma",
|
||||||
"fromEnvVar": null
|
"fromEnvVar": null
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
@ -384,7 +384,7 @@ const config = {
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"previewFeatures": [],
|
"previewFeatures": [],
|
||||||
"sourceFilePath": "C:\\Users\\Rother\\fork\\ironie-nextjs\\prisma\\schema.prisma",
|
"sourceFilePath": "C:\\Users\\Chris\\fork\\ironie-nextjs\\prisma\\schema.prisma",
|
||||||
"isCustomOutput": true
|
"isCustomOutput": true
|
||||||
},
|
},
|
||||||
"relativeEnvPaths": {
|
"relativeEnvPaths": {
|
||||||
@ -392,12 +392,13 @@ const config = {
|
|||||||
"schemaEnvPath": "../../../.env"
|
"schemaEnvPath": "../../../.env"
|
||||||
},
|
},
|
||||||
"relativePath": "../../../prisma",
|
"relativePath": "../../../prisma",
|
||||||
"clientVersion": "6.16.2",
|
"clientVersion": "6.16.1",
|
||||||
"engineVersion": "1c57fdcd7e44b29b9313256c76699e91c3ac3c43",
|
"engineVersion": "1c57fdcd7e44b29b9313256c76699e91c3ac3c43",
|
||||||
"datasourceNames": [
|
"datasourceNames": [
|
||||||
"db"
|
"db"
|
||||||
],
|
],
|
||||||
"activeProvider": "postgresql",
|
"activeProvider": "postgresql",
|
||||||
|
"postinstall": false,
|
||||||
"inlineDatasources": {
|
"inlineDatasources": {
|
||||||
"db": {
|
"db": {
|
||||||
"url": {
|
"url": {
|
||||||
|
|||||||
@ -20,11 +20,11 @@ exports.Prisma = Prisma
|
|||||||
exports.$Enums = {}
|
exports.$Enums = {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prisma Client JS version: 6.16.2
|
* Prisma Client JS version: 6.16.1
|
||||||
* Query Engine version: 1c57fdcd7e44b29b9313256c76699e91c3ac3c43
|
* Query Engine version: 1c57fdcd7e44b29b9313256c76699e91c3ac3c43
|
||||||
*/
|
*/
|
||||||
Prisma.prismaVersion = {
|
Prisma.prismaVersion = {
|
||||||
client: "6.16.2",
|
client: "6.16.1",
|
||||||
engine: "1c57fdcd7e44b29b9313256c76699e91c3ac3c43"
|
engine: "1c57fdcd7e44b29b9313256c76699e91c3ac3c43"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
2
src/generated/prisma/index.d.ts
vendored
2
src/generated/prisma/index.d.ts
vendored
@ -460,7 +460,7 @@ export namespace Prisma {
|
|||||||
export import Exact = $Public.Exact
|
export import Exact = $Public.Exact
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prisma Client JS version: 6.16.2
|
* Prisma Client JS version: 6.16.1
|
||||||
* Query Engine version: 1c57fdcd7e44b29b9313256c76699e91c3ac3c43
|
* Query Engine version: 1c57fdcd7e44b29b9313256c76699e91c3ac3c43
|
||||||
*/
|
*/
|
||||||
export type PrismaVersion = {
|
export type PrismaVersion = {
|
||||||
|
|||||||
@ -35,11 +35,11 @@ exports.Prisma = Prisma
|
|||||||
exports.$Enums = {}
|
exports.$Enums = {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prisma Client JS version: 6.16.2
|
* Prisma Client JS version: 6.16.1
|
||||||
* Query Engine version: 1c57fdcd7e44b29b9313256c76699e91c3ac3c43
|
* Query Engine version: 1c57fdcd7e44b29b9313256c76699e91c3ac3c43
|
||||||
*/
|
*/
|
||||||
Prisma.prismaVersion = {
|
Prisma.prismaVersion = {
|
||||||
client: "6.16.2",
|
client: "6.16.1",
|
||||||
engine: "1c57fdcd7e44b29b9313256c76699e91c3ac3c43"
|
engine: "1c57fdcd7e44b29b9313256c76699e91c3ac3c43"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -371,7 +371,7 @@ const config = {
|
|||||||
"value": "prisma-client-js"
|
"value": "prisma-client-js"
|
||||||
},
|
},
|
||||||
"output": {
|
"output": {
|
||||||
"value": "C:\\Users\\Rother\\fork\\ironie-nextjs\\src\\generated\\prisma",
|
"value": "C:\\Users\\Chris\\fork\\ironie-nextjs\\src\\generated\\prisma",
|
||||||
"fromEnvVar": null
|
"fromEnvVar": null
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
@ -385,7 +385,7 @@ const config = {
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"previewFeatures": [],
|
"previewFeatures": [],
|
||||||
"sourceFilePath": "C:\\Users\\Rother\\fork\\ironie-nextjs\\prisma\\schema.prisma",
|
"sourceFilePath": "C:\\Users\\Chris\\fork\\ironie-nextjs\\prisma\\schema.prisma",
|
||||||
"isCustomOutput": true
|
"isCustomOutput": true
|
||||||
},
|
},
|
||||||
"relativeEnvPaths": {
|
"relativeEnvPaths": {
|
||||||
@ -393,12 +393,13 @@ const config = {
|
|||||||
"schemaEnvPath": "../../../.env"
|
"schemaEnvPath": "../../../.env"
|
||||||
},
|
},
|
||||||
"relativePath": "../../../prisma",
|
"relativePath": "../../../prisma",
|
||||||
"clientVersion": "6.16.2",
|
"clientVersion": "6.16.1",
|
||||||
"engineVersion": "1c57fdcd7e44b29b9313256c76699e91c3ac3c43",
|
"engineVersion": "1c57fdcd7e44b29b9313256c76699e91c3ac3c43",
|
||||||
"datasourceNames": [
|
"datasourceNames": [
|
||||||
"db"
|
"db"
|
||||||
],
|
],
|
||||||
"activeProvider": "postgresql",
|
"activeProvider": "postgresql",
|
||||||
|
"postinstall": false,
|
||||||
"inlineDatasources": {
|
"inlineDatasources": {
|
||||||
"db": {
|
"db": {
|
||||||
"url": {
|
"url": {
|
||||||
|
|||||||
@ -151,7 +151,7 @@
|
|||||||
},
|
},
|
||||||
"./*": "./*"
|
"./*": "./*"
|
||||||
},
|
},
|
||||||
"version": "6.16.2",
|
"version": "6.16.1",
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
"imports": {
|
"imports": {
|
||||||
"#wasm-engine-loader": {
|
"#wasm-engine-loader": {
|
||||||
|
|||||||
BIN
src/generated/prisma/query_engine-windows.dll.node.tmp17904
Normal file
BIN
src/generated/prisma/query_engine-windows.dll.node.tmp17904
Normal file
Binary file not shown.
BIN
src/generated/prisma/query_engine-windows.dll.node.tmp24668
Normal file
BIN
src/generated/prisma/query_engine-windows.dll.node.tmp24668
Normal file
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
6
src/generated/prisma/runtime/react-native.js
vendored
6
src/generated/prisma/runtime/react-native.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -54,6 +54,9 @@ model User {
|
|||||||
pterodactylClientApiKey String?
|
pterodactylClientApiKey String?
|
||||||
|
|
||||||
timeZone String? // IANA-TZ, z.B. "Europe/Berlin"
|
timeZone String? // IANA-TZ, z.B. "Europe/Berlin"
|
||||||
|
|
||||||
|
// ✅ Datenschutz: darf eingeladen werden?
|
||||||
|
canBeInvited Boolean @default(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
enum UserStatus {
|
enum UserStatus {
|
||||||
@ -173,7 +176,7 @@ model MatchPlayer {
|
|||||||
teamId String?
|
teamId String?
|
||||||
team Team? @relation(fields: [teamId], references: [id])
|
team Team? @relation(fields: [teamId], references: [id])
|
||||||
|
|
||||||
match Match @relation(fields: [matchId], references: [id])
|
match Match @relation(fields: [matchId], references: [id], onDelete: Cascade)
|
||||||
user User @relation(fields: [steamId], references: [steamId])
|
user User @relation(fields: [steamId], references: [steamId])
|
||||||
|
|
||||||
stats PlayerStats?
|
stats PlayerStats?
|
||||||
@ -239,7 +242,7 @@ model RankHistory {
|
|||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
|
|
||||||
user User @relation("UserRankHistory", fields: [steamId], references: [steamId])
|
user User @relation("UserRankHistory", fields: [steamId], references: [steamId])
|
||||||
match Match? @relation("MatchRankHistory", fields: [matchId], references: [id])
|
match Match? @relation("MatchRankHistory", fields: [matchId], references: [id], onDelete: Cascade)
|
||||||
}
|
}
|
||||||
|
|
||||||
model Schedule {
|
model Schedule {
|
||||||
@ -263,7 +266,7 @@ model Schedule {
|
|||||||
confirmedBy User? @relation("ConfirmedSchedules", fields: [confirmedById], references: [steamId])
|
confirmedBy User? @relation("ConfirmedSchedules", fields: [confirmedById], references: [steamId])
|
||||||
|
|
||||||
linkedMatchId String? @unique
|
linkedMatchId String? @unique
|
||||||
linkedMatch Match? @relation(fields: [linkedMatchId], references: [id])
|
linkedMatch Match? @relation(fields: [linkedMatchId], references: [id], onDelete: Cascade)
|
||||||
|
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
@ -293,7 +296,7 @@ model DemoFile {
|
|||||||
|
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
|
|
||||||
match Match @relation(fields: [matchId], references: [id])
|
match Match @relation(fields: [matchId], references: [id], onDelete: Cascade)
|
||||||
user User @relation(fields: [steamId], references: [steamId])
|
user User @relation(fields: [steamId], references: [steamId])
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -326,7 +329,7 @@ enum MapVoteAction {
|
|||||||
model MapVote {
|
model MapVote {
|
||||||
id String @id @default(uuid())
|
id String @id @default(uuid())
|
||||||
matchId String @unique
|
matchId String @unique
|
||||||
match Match @relation(fields: [matchId], references: [id])
|
match Match @relation(fields: [matchId], references: [id], onDelete: Cascade)
|
||||||
|
|
||||||
bestOf Int @default(3)
|
bestOf Int @default(3)
|
||||||
mapPool String[]
|
mapPool String[]
|
||||||
@ -359,7 +362,7 @@ model MapVoteStep {
|
|||||||
chosenBy String?
|
chosenBy String?
|
||||||
chooser User? @relation("VoteStepChooser", fields: [chosenBy], references: [steamId])
|
chooser User? @relation("VoteStepChooser", fields: [chosenBy], references: [steamId])
|
||||||
|
|
||||||
vote MapVote @relation(fields: [voteId], references: [id])
|
vote MapVote @relation(fields: [voteId], references: [id], onDelete: Cascade)
|
||||||
|
|
||||||
@@unique([voteId, order])
|
@@unique([voteId, order])
|
||||||
@@index([teamId])
|
@@index([teamId])
|
||||||
@ -371,7 +374,7 @@ model MatchReady {
|
|||||||
steamId String
|
steamId String
|
||||||
acceptedAt DateTime @default(now())
|
acceptedAt DateTime @default(now())
|
||||||
|
|
||||||
match Match @relation("MatchReadyMatch", fields: [matchId], references: [id])
|
match Match @relation("MatchReadyMatch", fields: [matchId], references: [id], onDelete: Cascade)
|
||||||
user User @relation("MatchReadyUser", fields: [steamId], references: [steamId])
|
user User @relation("MatchReadyUser", fields: [steamId], references: [steamId])
|
||||||
|
|
||||||
@@id([matchId, steamId])
|
@@id([matchId, steamId])
|
||||||
|
|||||||
@ -35,11 +35,11 @@ exports.Prisma = Prisma
|
|||||||
exports.$Enums = {}
|
exports.$Enums = {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prisma Client JS version: 6.16.2
|
* Prisma Client JS version: 6.16.1
|
||||||
* Query Engine version: 1c57fdcd7e44b29b9313256c76699e91c3ac3c43
|
* Query Engine version: 1c57fdcd7e44b29b9313256c76699e91c3ac3c43
|
||||||
*/
|
*/
|
||||||
Prisma.prismaVersion = {
|
Prisma.prismaVersion = {
|
||||||
client: "6.16.2",
|
client: "6.16.1",
|
||||||
engine: "1c57fdcd7e44b29b9313256c76699e91c3ac3c43"
|
engine: "1c57fdcd7e44b29b9313256c76699e91c3ac3c43"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -370,7 +370,7 @@ const config = {
|
|||||||
"value": "prisma-client-js"
|
"value": "prisma-client-js"
|
||||||
},
|
},
|
||||||
"output": {
|
"output": {
|
||||||
"value": "C:\\Users\\Rother\\fork\\ironie-nextjs\\src\\generated\\prisma",
|
"value": "C:\\Users\\Chris\\fork\\ironie-nextjs\\src\\generated\\prisma",
|
||||||
"fromEnvVar": null
|
"fromEnvVar": null
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
@ -384,7 +384,7 @@ const config = {
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"previewFeatures": [],
|
"previewFeatures": [],
|
||||||
"sourceFilePath": "C:\\Users\\Rother\\fork\\ironie-nextjs\\prisma\\schema.prisma",
|
"sourceFilePath": "C:\\Users\\Chris\\fork\\ironie-nextjs\\prisma\\schema.prisma",
|
||||||
"isCustomOutput": true
|
"isCustomOutput": true
|
||||||
},
|
},
|
||||||
"relativeEnvPaths": {
|
"relativeEnvPaths": {
|
||||||
@ -392,12 +392,13 @@ const config = {
|
|||||||
"schemaEnvPath": "../../../.env"
|
"schemaEnvPath": "../../../.env"
|
||||||
},
|
},
|
||||||
"relativePath": "../../../prisma",
|
"relativePath": "../../../prisma",
|
||||||
"clientVersion": "6.16.2",
|
"clientVersion": "6.16.1",
|
||||||
"engineVersion": "1c57fdcd7e44b29b9313256c76699e91c3ac3c43",
|
"engineVersion": "1c57fdcd7e44b29b9313256c76699e91c3ac3c43",
|
||||||
"datasourceNames": [
|
"datasourceNames": [
|
||||||
"db"
|
"db"
|
||||||
],
|
],
|
||||||
"activeProvider": "postgresql",
|
"activeProvider": "postgresql",
|
||||||
|
"postinstall": false,
|
||||||
"inlineDatasources": {
|
"inlineDatasources": {
|
||||||
"db": {
|
"db": {
|
||||||
"url": {
|
"url": {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user