Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion apps/client/src/hooks/useEvent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ const GET_EVENT = gql`
}
date
timezone
zeroTime
discipline
externalSource
externalEventId
Expand Down
4 changes: 2 additions & 2 deletions apps/client/src/pages/Event/EventInfoView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -156,11 +156,11 @@ export function EventInfoView({ event }: EventInfoViewProps) {
<div className="font-medium">
{formatDate(event.date, localeKey)}
</div>
{event.zeroTime && (
{event.date && (
<div className="text-sm text-muted-foreground mt-1">
{t('Pages.Event.Detail.ZeroTime')}:{' '}
{formatStoredUtcTimeForTimezone(
event.zeroTime,
new Date(event.date).toISOString().slice(11, 19),
event.date,
event.timezone || 'UTC'
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -366,8 +366,7 @@ export const EventExternalLinkCard: React.FC<EventExternalLinkCardProps> = ({
!date ||
!timezone ||
!organizer ||
!location ||
!zeroTime
!location
) {
toast({
title: t('Operations.Error', { ns: 'common' }),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,7 @@ export const EventPublishingScheduleCard: React.FC<
!eventData.date ||
!eventData.timezone ||
!eventData.organizer ||
!eventData.location ||
!eventData.zeroTime
!eventData.location
) {
toast({
title: t('Operations.Error', { ns: 'common' }),
Expand All @@ -157,7 +156,7 @@ export const EventPublishingScheduleCard: React.FC<
latitude: eventData.latitude,
longitude: eventData.longitude,
countryCode: eventData.country?.countryCode || undefined,
zeroTime: eventData.zeroTime,
zeroTime: new Date(eventData.date).toISOString().slice(11, 19),
discipline: eventData.discipline,
ranking: eventData.ranking,
coefRanking: eventData.coefRanking,
Expand Down
9 changes: 5 additions & 4 deletions apps/client/src/pages/Event/Settings/EventSettingsPage.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { config } from '@/config';
import { formatDate, formatDateForInput } from '@/lib/utils';
import { formatDate } from '@/lib/utils';
import { gql } from '@apollo/client';
import { useQuery } from '@apollo/client/react';
import { useParams } from '@tanstack/react-router';
Expand Down Expand Up @@ -42,7 +42,6 @@ export const GET_EVENT = gql`
sportId
date
timezone
zeroTime
discipline
externalSource
externalEventId
Expand Down Expand Up @@ -110,14 +109,16 @@ export const EventSettingsPage = () => {
id: data.event.id,
name: data.event.name,
sportId: data.event.sportId,
date: formatDateForInput(data.event.date),
date: data.event.date ? data.event.date.slice(0, 10) : '',
timezone: data.event.timezone || 'Europe/Prague',
organizer: data.event.organizer,
location: data.event.location,
latitude: data.event.latitude,
longitude: data.event.longitude,
countryCode: data.event.country?.countryCode || '',
zeroTime: data.event.zeroTime ?? '',
zeroTime: data.event.date
? new Date(data.event.date).toISOString().slice(11, 19)
: '',
discipline: data.event.discipline,
ranking: data.event.ranking || false,
coefRanking: data.event.coefRanking,
Expand Down
1 change: 0 additions & 1 deletion apps/client/src/types/event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ export interface Event {
sportId: number;
sport: EventSport;
discipline: EventDiscipline;
zeroTime?: string; // UTC time-of-day (HH:mm:ss)
timezone?: string; // IANA timezone (e.g., 'Europe/Prague', 'America/New_York')
externalSource?: 'ORIS' | 'EVENTOR';
externalEventId?: string;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
-- Merge separate date (DATE) and zeroTime (TIME) columns into a single DATETIME column.
-- The new `date` stores the UTC event start timestamp.
ALTER TABLE `event` ADD COLUMN `date_tmp` DATETIME(0) NOT NULL DEFAULT '1970-01-01 00:00:00' AFTER `organizer`;
UPDATE `event` SET `date_tmp` = TIMESTAMP(DATE(`date`), `zeroTime`);
ALTER TABLE `event` DROP COLUMN `zeroTime`;
ALTER TABLE `event` DROP COLUMN `date`;
ALTER TABLE `event` CHANGE `date_tmp` `date` DATETIME(0) NOT NULL AFTER `organizer`;
167 changes: 83 additions & 84 deletions apps/server/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,18 @@ model Country {
}

model RankingCzech {
id Int @id @default(autoincrement()) @db.UnsignedInt
id Int @id @default(autoincrement()) @db.UnsignedInt
rankingType CzechRankingType
rankingCategory CzechRankingCategory
validForMonth DateTime @db.Date
validForMonth DateTime @db.Date
place Int
firstName String
lastName String
registration String @db.VarChar(10)
registration String @db.VarChar(10)
points Int
rankIndex Int
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt

@@unique([registration, rankingType, rankingCategory, validForMonth], map: "ranking_czech_reg_type_cat_month_uq")
@@index([rankingType, rankingCategory, validForMonth], map: "ranking_czech_type_cat_month_idx")
Expand Down Expand Up @@ -65,9 +65,9 @@ model CzechRankingEventResult {
}

model Sport {
id Int @id @default(autoincrement()) @db.UnsignedInt
name String @unique
events Event[]
id Int @id @default(autoincrement()) @db.UnsignedInt
name String @unique
events Event[]
userCards UserCard[]
}

Expand Down Expand Up @@ -104,9 +104,9 @@ model UserCard {
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt

@@unique([userId, sportId, type, cardNumber])
@@index([userId, sportId])
@@index([userId, sportId, isDefault])
@@unique([userId, sportId, type, cardNumber])
}

enum UserCardType {
Expand All @@ -119,47 +119,46 @@ enum UserRole {
}

model Event {
id String @id @default(cuid())
sport Sport @relation(fields: [sportId], references: [id])
sportId Int @db.UnsignedInt
name String
organizer String?
date DateTime @db.Date
timezone String @default("Europe/Prague")
location String?
latitude Float? // GPS Latitude (nullable)
longitude Float? // GPS Longitude (nullable)
countryId String? @db.Char(2)
country Country? @relation(fields: [countryId], references: [countryCode])
externalSource ExternalSource?
externalEventId String? @db.VarChar(128)
featuredImageKey String? @db.VarChar(512)
zeroTime DateTime @db.Time(0)
relay Boolean @default(false)
discipline EventDiscipline @default(OTHER)
startMode StartMode @default(Individual)
ranking Boolean @default(false)
coefRanking Float?
hundredthPrecision Boolean @default(false) // Measure finish time in hundredths of a second
published Boolean @default(false)
demo Boolean @default(false)
entriesOpenAt DateTime?
entriesCloseAt DateTime?
splitPublicationMode SplitPublicationMode @default(UNRESTRICTED)
splitPublicationAt DateTime?
resultsOfficialAt DateTime?
id String @id @default(cuid())
sport Sport @relation(fields: [sportId], references: [id])
sportId Int @db.UnsignedInt
name String
organizer String?
date DateTime @db.DateTime(0)
timezone String @default("Europe/Prague")
location String?
latitude Float? // GPS Latitude (nullable)
longitude Float? // GPS Longitude (nullable)
countryId String? @db.Char(2)
country Country? @relation(fields: [countryId], references: [countryCode])
externalSource ExternalSource?
externalEventId String? @db.VarChar(128)
featuredImageKey String? @db.VarChar(512)
relay Boolean @default(false)
discipline EventDiscipline @default(OTHER)
startMode StartMode @default(Individual)
ranking Boolean @default(false)
coefRanking Float?
hundredthPrecision Boolean @default(false) // Measure finish time in hundredths of a second
published Boolean @default(false)
demo Boolean @default(false)
entriesOpenAt DateTime?
entriesCloseAt DateTime?
splitPublicationMode SplitPublicationMode @default(UNRESTRICTED)
splitPublicationAt DateTime?
resultsOfficialAt DateTime?
resultsOfficialManuallySetAt DateTime?
author User? @relation(fields: [authorId], references: [id])
authorId Int? @db.UnsignedInt
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
classes Class[]
protocols Protocol[]
eventPasswords EventPassword[]
externalResultsSync EventExternalResultsSyncState?
author User? @relation(fields: [authorId], references: [id])
authorId Int? @db.UnsignedInt
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
classes Class[]
protocols Protocol[]
eventPasswords EventPassword[]
externalResultsSync EventExternalResultsSyncState?

@@fulltext([name, organizer, location])
@@index([externalSource, externalEventId])
@@fulltext([name, organizer, location])
}

model Class {
Expand All @@ -185,33 +184,33 @@ model Class {
}

model Competitor {
id Int @id @default(autoincrement()) @db.UnsignedInt
class Class @relation(fields: [classId], references: [id])
classId Int @db.UnsignedInt
firstname String
lastname String
bibNumber Int?
nationality String? @db.Char(3)
registration String @db.VarChar(10)
license String? @db.Char(1)
rankingPoints Int? @db.UnsignedInt
rankingReferenceValue Int? @db.UnsignedInt
organisation String?
shortName String? @db.VarChar(10)
card Int? @db.UnsignedInt
startTime DateTime?
finishTime DateTime?
time Int?
team Team? @relation(fields: [teamId], references: [id])
teamId Int? @db.UnsignedInt
leg Int? @db.UnsignedInt
status ResultStatus @default(Inactive)
lateStart Boolean @default(false)
note String?
updatedAt DateTime @default(now()) @updatedAt
externalId String?
protocols Protocol[]
splits Split[]
id Int @id @default(autoincrement()) @db.UnsignedInt
class Class @relation(fields: [classId], references: [id])
classId Int @db.UnsignedInt
firstname String
lastname String
bibNumber Int?
nationality String? @db.Char(3)
registration String @db.VarChar(10)
license String? @db.Char(1)
rankingPoints Int? @db.UnsignedInt
rankingReferenceValue Int? @db.UnsignedInt
organisation String?
shortName String? @db.VarChar(10)
card Int? @db.UnsignedInt
startTime DateTime?
finishTime DateTime?
time Int?
team Team? @relation(fields: [teamId], references: [id])
teamId Int? @db.UnsignedInt
leg Int? @db.UnsignedInt
status ResultStatus @default(Inactive)
lateStart Boolean @default(false)
note String?
updatedAt DateTime @default(now()) @updatedAt
externalId String?
protocols Protocol[]
splits Split[]
}

model Split {
Expand Down Expand Up @@ -259,17 +258,17 @@ model EventPassword {
}

model EventExternalResultsSyncState {
id Int @id @default(autoincrement()) @db.UnsignedInt
event Event @relation(fields: [eventId], references: [id])
eventId String @unique
provider ExternalSource
lastCheckedAt DateTime?
lastSuccessfulCheckAt DateTime?
id Int @id @default(autoincrement()) @db.UnsignedInt
event Event @relation(fields: [eventId], references: [id])
eventId String @unique
provider ExternalSource
lastCheckedAt DateTime?
lastSuccessfulCheckAt DateTime?
lastDetectedOfficialAt DateTime?
lastStatus ExternalResultsSyncStatus @default(PENDING)
lastError String? @db.Text
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
lastStatus ExternalResultsSyncStatus @default(PENDING)
lastError String? @db.Text
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt

@@index([provider, lastStatus])
}
Expand Down
2 changes: 1 addition & 1 deletion apps/server/src/graphql/event/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ const resolvers = {
}
return decryptedPassword;
},
zeroTime: (parent) => normalizeUtcTimeString(parent.zeroTime) ?? '00:00:00',
zeroTime: (parent) => normalizeUtcTimeString(parent.date) ?? '00:00:00',
featuredImage: (parent) => buildPublicImageUrl(parent.featuredImageKey, parent.id),
statusSummary: (parent) => getEventStatusSummary(prisma, parent),
},
Expand Down
4 changes: 2 additions & 2 deletions apps/server/src/graphql/event/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,14 +126,14 @@ export const typeDef = /* GraphQL */ `
sportId: Int!
name: String!
organizer: String
date: Date!
date: DateTime!
timezone: String!
zeroTime: String!
externalSource: ExternalEventProvider
externalEventId: String
location: String
latitude: Float
longitude: Float
zeroTime: String!
relay: Boolean!
discipline: EventDiscipline!
ranking: Boolean!
Expand Down
Loading
Loading