view data fixes
This commit is contained in:
@@ -24,7 +24,7 @@ module.exports = {
|
|||||||
|
|
||||||
create(context) {
|
create(context) {
|
||||||
const filename = context.getFilename();
|
const filename = context.getFilename();
|
||||||
const isInViewData = filename.includes('/lib/view-data/');
|
const isInViewData = filename.includes('/lib/view-data/') && !filename.includes('/contracts/');
|
||||||
|
|
||||||
if (!isInViewData) return {};
|
if (!isInViewData) return {};
|
||||||
|
|
||||||
@@ -42,9 +42,15 @@ module.exports = {
|
|||||||
// Check if it extends ViewData
|
// Check if it extends ViewData
|
||||||
if (node.extends && node.extends.length > 0) {
|
if (node.extends && node.extends.length > 0) {
|
||||||
for (const ext of node.extends) {
|
for (const ext of node.extends) {
|
||||||
if (ext.type === 'TSExpressionWithTypeArguments' &&
|
// Use context.getSourceCode().getText(ext) to be absolutely sure
|
||||||
ext.expression.type === 'Identifier' &&
|
const extendsText = context.getSourceCode().getText(ext).trim();
|
||||||
ext.expression.name === 'ViewData') {
|
// We check for 'ViewData' but must be careful not to match 'SomethingViewData'
|
||||||
|
// unless it's exactly 'ViewData' or part of a qualified name
|
||||||
|
if (extendsText === 'ViewData' ||
|
||||||
|
extendsText.endsWith('.ViewData') ||
|
||||||
|
extendsText.startsWith('ViewData<') ||
|
||||||
|
extendsText.startsWith('ViewData ') ||
|
||||||
|
/\bViewData\b/.test(extendsText)) { // Use regex for word boundary
|
||||||
hasViewDataExtends = true;
|
hasViewDataExtends = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -74,16 +80,31 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
'Program:exit'() {
|
'Program:exit'() {
|
||||||
if (!hasCorrectName) {
|
// Only report if we are in a file that should be a ViewData
|
||||||
|
// and we didn't find a valid declaration
|
||||||
|
const baseName = filename.split('/').pop();
|
||||||
|
|
||||||
|
// All files in lib/view-data/ must end with ViewData.ts
|
||||||
|
if (baseName && !baseName.endsWith('ViewData.ts') && !baseName.endsWith('ViewData.tsx')) {
|
||||||
context.report({
|
context.report({
|
||||||
node: context.getSourceCode().ast,
|
node: context.getSourceCode().ast,
|
||||||
messageId: 'notAnInterface',
|
messageId: 'notAnInterface',
|
||||||
});
|
});
|
||||||
} else if (!hasViewDataExtends) {
|
return;
|
||||||
context.report({
|
}
|
||||||
node: context.getSourceCode().ast,
|
|
||||||
messageId: 'missingExtends',
|
if (baseName && (baseName.endsWith('ViewData.ts') || baseName.endsWith('ViewData.tsx'))) {
|
||||||
});
|
if (!hasCorrectName) {
|
||||||
|
context.report({
|
||||||
|
node: context.getSourceCode().ast,
|
||||||
|
messageId: 'notAnInterface',
|
||||||
|
});
|
||||||
|
} else if (!hasViewDataExtends) {
|
||||||
|
context.report({
|
||||||
|
node: context.getSourceCode().ast,
|
||||||
|
messageId: 'missingExtends',
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,25 +1,28 @@
|
|||||||
/**
|
/**
|
||||||
* ViewData Builder Contract
|
* ViewData Builder Contract
|
||||||
*
|
*
|
||||||
* Purpose: Transform ViewModels into ViewData for templates
|
* Purpose: Transform API Transport DTOs into ViewData for templates
|
||||||
*
|
*
|
||||||
* Rules:
|
* Rules:
|
||||||
* - Deterministic and side-effect free
|
* - Deterministic and side-effect free
|
||||||
* - No HTTP/API calls
|
* - No HTTP/API calls
|
||||||
* - Input: ViewModel
|
* - Input: API Transport DTO (must be JSON-serializable)
|
||||||
* - Output: ViewData (JSON-serializable)
|
* - Output: ViewData (JSON-serializable template-ready data)
|
||||||
* - Must be in lib/builders/view-data/
|
* - Must be in lib/builders/view-data/
|
||||||
* - Must be named *ViewDataBuilder
|
* - Must be named *ViewDataBuilder
|
||||||
* - Must have 'use client' directive
|
* - Must have 'use client' directive
|
||||||
* - Must implement static build() method
|
* - Must implement static build() method
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export interface ViewDataBuilder<TInput, TOutput> {
|
import { JsonValue } from '../types/primitives';
|
||||||
|
import { ViewData } from '../view-data/ViewData';
|
||||||
|
|
||||||
|
export interface ViewDataBuilder<TDTO extends JsonValue, TViewData extends ViewData> {
|
||||||
/**
|
/**
|
||||||
* Transform ViewModel into ViewData
|
* Transform DTO into ViewData
|
||||||
*
|
*
|
||||||
* @param viewModel - Client-side ViewModel
|
* @param dto - API Transport DTO (JSON-serializable)
|
||||||
* @returns ViewData for template
|
* @returns ViewData for template
|
||||||
*/
|
*/
|
||||||
build(viewModel: TInput): TOutput;
|
build(dto: TDTO): TViewData;
|
||||||
}
|
}
|
||||||
@@ -1,25 +1,28 @@
|
|||||||
/**
|
/**
|
||||||
* ViewModel Builder Contract
|
* ViewModel Builder Contract
|
||||||
*
|
*
|
||||||
* Purpose: Transform API Transport DTOs into ViewModels
|
* Purpose: Transform ViewData into ViewModels for client-side state management
|
||||||
*
|
*
|
||||||
* Rules:
|
* Rules:
|
||||||
* - Deterministic and side-effect free
|
* - Deterministic and side-effect free
|
||||||
* - No HTTP/API calls
|
* - No HTTP/API calls
|
||||||
* - Input: API Transport DTO
|
* - Input: ViewData (JSON-serializable template-ready data)
|
||||||
* - Output: ViewModel
|
* - Output: ViewModel (client-only class)
|
||||||
* - Must be in lib/builders/view-models/
|
* - Must be in lib/builders/view-models/
|
||||||
* - Must be named *ViewModelBuilder
|
* - Must be named *ViewModelBuilder
|
||||||
* - Must have 'use client' directive
|
* - Must have 'use client' directive
|
||||||
* - Must implement static build() method
|
* - Must implement static build() method
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export interface ViewModelBuilder<TInput, TOutput> {
|
import { ViewData } from '../view-data/ViewData';
|
||||||
|
import { ViewModel } from '../view-models/ViewModel';
|
||||||
|
|
||||||
|
export interface ViewModelBuilder<TViewData extends ViewData, TViewModel extends ViewModel> {
|
||||||
/**
|
/**
|
||||||
* Transform DTO into ViewModel
|
* Transform ViewData into ViewModel
|
||||||
*
|
*
|
||||||
* @param dto - API Transport DTO
|
* @param viewData - ViewData (JSON-serializable template-ready data)
|
||||||
* @returns ViewModel
|
* @returns ViewModel
|
||||||
*/
|
*/
|
||||||
build(dto: TInput): TOutput;
|
build(viewData: TViewData): TViewModel;
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* Base interface for ViewData objects
|
* Base interface for ViewData objects
|
||||||
*
|
*
|
||||||
* All ViewData must be JSON-serializable.
|
* All ViewData must be JSON-serializable.
|
||||||
* This type ensures no class instances or functions are included.
|
* This type ensures no class instances or functions are included.
|
||||||
*/
|
*/
|
||||||
@@ -10,7 +10,7 @@ export interface ViewData {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper type to ensure a type is ViewData-compatible
|
* Helper type to ensure a type is ViewData-compatible
|
||||||
*
|
*
|
||||||
* Usage:
|
* Usage:
|
||||||
* ```typescript
|
* ```typescript
|
||||||
* type MyViewData = ViewData & {
|
* type MyViewData = ViewData & {
|
||||||
|
|||||||
33
apps/website/lib/display-objects/ActivityLevelDisplay.ts
Normal file
33
apps/website/lib/display-objects/ActivityLevelDisplay.ts
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
/**
|
||||||
|
* ActivityLevelDisplay
|
||||||
|
*
|
||||||
|
* Deterministic mapping of engagement rates to activity level labels.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export class ActivityLevelDisplay {
|
||||||
|
/**
|
||||||
|
* Maps engagement rate to activity level label.
|
||||||
|
*/
|
||||||
|
static levelLabel(engagementRate: number): string {
|
||||||
|
if (engagementRate < 20) {
|
||||||
|
return 'Low';
|
||||||
|
} else if (engagementRate < 50) {
|
||||||
|
return 'Medium';
|
||||||
|
} else {
|
||||||
|
return 'High';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps engagement rate to activity level value.
|
||||||
|
*/
|
||||||
|
static levelValue(engagementRate: number): 'low' | 'medium' | 'high' {
|
||||||
|
if (engagementRate < 20) {
|
||||||
|
return 'low';
|
||||||
|
} else if (engagementRate < 50) {
|
||||||
|
return 'medium';
|
||||||
|
} else {
|
||||||
|
return 'high';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
37
apps/website/lib/display-objects/AvatarDisplay.ts
Normal file
37
apps/website/lib/display-objects/AvatarDisplay.ts
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
/**
|
||||||
|
* AvatarDisplay
|
||||||
|
*
|
||||||
|
* Deterministic mapping of avatar-related data to display formats.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export class AvatarDisplay {
|
||||||
|
/**
|
||||||
|
* Converts binary buffer to base64 string for display.
|
||||||
|
*/
|
||||||
|
static bufferToBase64(buffer: ArrayBuffer): string {
|
||||||
|
const bytes = new Uint8Array(buffer);
|
||||||
|
let binary = '';
|
||||||
|
for (let i = 0; i < bytes.byteLength; i++) {
|
||||||
|
binary += String.fromCharCode(bytes[i]);
|
||||||
|
}
|
||||||
|
return btoa(binary);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if avatar data is valid for display.
|
||||||
|
*/
|
||||||
|
static hasValidData(buffer: ArrayBuffer, contentType: string): boolean {
|
||||||
|
return buffer.byteLength > 0 && contentType.length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats content type for display (e.g., "image/png" → "PNG").
|
||||||
|
*/
|
||||||
|
static formatContentType(contentType: string): string {
|
||||||
|
const parts = contentType.split('/');
|
||||||
|
if (parts.length === 2) {
|
||||||
|
return parts[1].toUpperCase();
|
||||||
|
}
|
||||||
|
return contentType;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,36 +1,47 @@
|
|||||||
/**
|
/**
|
||||||
* CurrencyDisplay
|
* CurrencyDisplay
|
||||||
*
|
*
|
||||||
* Deterministic currency formatting for display.
|
* Deterministic currency formatting for display.
|
||||||
* Avoids Intl and toLocaleString to prevent SSR/hydration mismatches.
|
* Avoids Intl and toLocaleString to prevent SSR/hydration mismatches.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export class CurrencyDisplay {
|
export class CurrencyDisplay {
|
||||||
/**
|
/**
|
||||||
* Formats an amount as currency (e.g., "$10.00").
|
* Formats an amount as currency (e.g., "$10.00" or "€1.000,00").
|
||||||
* Default currency is USD.
|
* Default currency is USD.
|
||||||
*/
|
*/
|
||||||
static format(amount: number, currency: string = 'USD'): string {
|
static format(amount: number, currency: string = 'USD'): string {
|
||||||
const symbol = currency === 'USD' ? '$' : currency + ' ';
|
const symbol = currency === 'USD' ? '$' : currency === 'EUR' ? '€' : currency + ' ';
|
||||||
const formattedAmount = amount.toFixed(2);
|
const formattedAmount = amount.toFixed(2);
|
||||||
|
|
||||||
// Add thousands separators
|
// Add thousands separators
|
||||||
const parts = formattedAmount.split('.');
|
const parts = formattedAmount.split('.');
|
||||||
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',');
|
|
||||||
|
|
||||||
return `${symbol}${parts.join('.')}`;
|
// Use dot as thousands separator for EUR, comma for USD
|
||||||
|
if (currency === 'EUR') {
|
||||||
|
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, '.');
|
||||||
|
return `${symbol}${parts[0]},${parts[1]}`;
|
||||||
|
} else {
|
||||||
|
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',');
|
||||||
|
return `${symbol}${parts.join('.')}`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Formats an amount as a compact currency (e.g., "$10").
|
* Formats an amount as a compact currency (e.g., "$10" or "€1.000").
|
||||||
*/
|
*/
|
||||||
static formatCompact(amount: number, currency: string = 'USD'): string {
|
static formatCompact(amount: number, currency: string = 'USD'): string {
|
||||||
const symbol = currency === 'USD' ? '$' : currency + ' ';
|
const symbol = currency === 'USD' ? '$' : currency === 'EUR' ? '€' : currency + ' ';
|
||||||
const roundedAmount = Math.round(amount);
|
const roundedAmount = Math.round(amount);
|
||||||
|
|
||||||
// Add thousands separators
|
// Add thousands separators
|
||||||
const formattedAmount = roundedAmount.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
|
const formattedAmount = roundedAmount.toString();
|
||||||
|
|
||||||
return `${symbol}${formattedAmount}`;
|
// Use dot as thousands separator for EUR, comma for USD
|
||||||
|
if (currency === 'EUR') {
|
||||||
|
return `${symbol}${formattedAmount.replace(/\B(?=(\d{3})+(?!\d))/g, '.')}`;
|
||||||
|
} else {
|
||||||
|
return `${symbol}${formattedAmount.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
39
apps/website/lib/display-objects/LeagueTierDisplay.ts
Normal file
39
apps/website/lib/display-objects/LeagueTierDisplay.ts
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/**
|
||||||
|
* LeagueTierDisplay
|
||||||
|
*
|
||||||
|
* Deterministic display logic for league tiers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export interface LeagueTierDisplayData {
|
||||||
|
color: string;
|
||||||
|
bgColor: string;
|
||||||
|
border: string;
|
||||||
|
icon: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class LeagueTierDisplay {
|
||||||
|
private static readonly CONFIG: Record<string, LeagueTierDisplayData> = {
|
||||||
|
premium: {
|
||||||
|
color: 'text-yellow-400',
|
||||||
|
bgColor: 'bg-yellow-500/10',
|
||||||
|
border: 'border-yellow-500/30',
|
||||||
|
icon: '⭐'
|
||||||
|
},
|
||||||
|
standard: {
|
||||||
|
color: 'text-primary-blue',
|
||||||
|
bgColor: 'bg-primary-blue/10',
|
||||||
|
border: 'border-primary-blue/30',
|
||||||
|
icon: '🏆'
|
||||||
|
},
|
||||||
|
starter: {
|
||||||
|
color: 'text-gray-400',
|
||||||
|
bgColor: 'bg-gray-500/10',
|
||||||
|
border: 'border-gray-500/30',
|
||||||
|
icon: '🚀'
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static getDisplay(tier: 'premium' | 'standard' | 'starter'): LeagueTierDisplayData {
|
||||||
|
return this.CONFIG[tier];
|
||||||
|
}
|
||||||
|
}
|
||||||
38
apps/website/lib/display-objects/OnboardingStatusDisplay.ts
Normal file
38
apps/website/lib/display-objects/OnboardingStatusDisplay.ts
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
/**
|
||||||
|
* OnboardingStatusDisplay
|
||||||
|
*
|
||||||
|
* Deterministic mapping of onboarding status to display labels and variants.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export class OnboardingStatusDisplay {
|
||||||
|
/**
|
||||||
|
* Maps onboarding success status to display label.
|
||||||
|
*/
|
||||||
|
static statusLabel(success: boolean): string {
|
||||||
|
return success ? 'Onboarding Complete' : 'Onboarding Failed';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps onboarding success status to badge variant.
|
||||||
|
*/
|
||||||
|
static statusVariant(success: boolean): string {
|
||||||
|
return success ? 'performance-green' : 'racing-red';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps onboarding success status to icon.
|
||||||
|
*/
|
||||||
|
static statusIcon(success: boolean): string {
|
||||||
|
return success ? '✅' : '❌';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps onboarding success status to message.
|
||||||
|
*/
|
||||||
|
static statusMessage(success: boolean, errorMessage?: string): string {
|
||||||
|
if (success) {
|
||||||
|
return 'Your onboarding has been completed successfully.';
|
||||||
|
}
|
||||||
|
return errorMessage || 'Failed to complete onboarding. Please try again.';
|
||||||
|
}
|
||||||
|
}
|
||||||
35
apps/website/lib/display-objects/SeasonStatusDisplay.ts
Normal file
35
apps/website/lib/display-objects/SeasonStatusDisplay.ts
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
/**
|
||||||
|
* SeasonStatusDisplay
|
||||||
|
*
|
||||||
|
* Deterministic display logic for season status.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export interface SeasonStatusDisplayData {
|
||||||
|
color: string;
|
||||||
|
bg: string;
|
||||||
|
label: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SeasonStatusDisplay {
|
||||||
|
private static readonly CONFIG: Record<string, SeasonStatusDisplayData> = {
|
||||||
|
active: {
|
||||||
|
color: 'text-performance-green',
|
||||||
|
bg: 'bg-performance-green/10',
|
||||||
|
label: 'Active Season'
|
||||||
|
},
|
||||||
|
upcoming: {
|
||||||
|
color: 'text-warning-amber',
|
||||||
|
bg: 'bg-warning-amber/10',
|
||||||
|
label: 'Starting Soon'
|
||||||
|
},
|
||||||
|
completed: {
|
||||||
|
color: 'text-gray-400',
|
||||||
|
bg: 'bg-gray-400/10',
|
||||||
|
label: 'Season Ended'
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static getDisplay(status: 'active' | 'upcoming' | 'completed'): SeasonStatusDisplayData {
|
||||||
|
return this.CONFIG[status];
|
||||||
|
}
|
||||||
|
}
|
||||||
19
apps/website/lib/display-objects/UserRoleDisplay.ts
Normal file
19
apps/website/lib/display-objects/UserRoleDisplay.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
/**
|
||||||
|
* UserRoleDisplay
|
||||||
|
*
|
||||||
|
* Deterministic mapping of user role codes to display labels.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export class UserRoleDisplay {
|
||||||
|
/**
|
||||||
|
* Maps user role to display label.
|
||||||
|
*/
|
||||||
|
static roleLabel(role: string): string {
|
||||||
|
const map: Record<string, string> = {
|
||||||
|
owner: 'Owner',
|
||||||
|
admin: 'Admin',
|
||||||
|
user: 'User',
|
||||||
|
};
|
||||||
|
return map[role] || role;
|
||||||
|
}
|
||||||
|
}
|
||||||
52
apps/website/lib/display-objects/UserStatusDisplay.ts
Normal file
52
apps/website/lib/display-objects/UserStatusDisplay.ts
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
/**
|
||||||
|
* UserStatusDisplay
|
||||||
|
*
|
||||||
|
* Deterministic mapping of user status codes to display labels and variants.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export class UserStatusDisplay {
|
||||||
|
/**
|
||||||
|
* Maps user status to display label.
|
||||||
|
*/
|
||||||
|
static statusLabel(status: string): string {
|
||||||
|
const map: Record<string, string> = {
|
||||||
|
active: 'Active',
|
||||||
|
suspended: 'Suspended',
|
||||||
|
deleted: 'Deleted',
|
||||||
|
};
|
||||||
|
return map[status] || status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps user status to badge variant.
|
||||||
|
*/
|
||||||
|
static statusVariant(status: string): string {
|
||||||
|
const map: Record<string, string> = {
|
||||||
|
active: 'performance-green',
|
||||||
|
suspended: 'yellow-500',
|
||||||
|
deleted: 'racing-red',
|
||||||
|
};
|
||||||
|
return map[status] || 'gray-500';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if a user can be suspended.
|
||||||
|
*/
|
||||||
|
static canSuspend(status: string): boolean {
|
||||||
|
return status === 'active';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if a user can be activated.
|
||||||
|
*/
|
||||||
|
static canActivate(status: string): boolean {
|
||||||
|
return status === 'suspended';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if a user can be deleted.
|
||||||
|
*/
|
||||||
|
static canDelete(status: string): boolean {
|
||||||
|
return status !== 'deleted';
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
|
import { ProtestDetailViewDataBuilder } from '@/lib/builders/view-data/ProtestDetailViewDataBuilder';
|
||||||
import { PageQuery } from '@/lib/contracts/page-queries/PageQuery';
|
import { PageQuery } from '@/lib/contracts/page-queries/PageQuery';
|
||||||
|
import { type PresentationError, mapToPresentationError } from '@/lib/contracts/page-queries/PresentationError';
|
||||||
import { Result } from '@/lib/contracts/Result';
|
import { Result } from '@/lib/contracts/Result';
|
||||||
import { ProtestDetailService } from '@/lib/services/leagues/ProtestDetailService';
|
import { ProtestDetailService } from '@/lib/services/leagues/ProtestDetailService';
|
||||||
import { ProtestDetailViewDataBuilder } from '@/lib/builders/view-data/ProtestDetailViewDataBuilder';
|
import { ProtestDetailViewData } from '@/lib/view-data/ProtestDetailViewData';
|
||||||
import { ProtestDetailViewData } from '@/lib/view-data/leagues/ProtestDetailViewData';
|
|
||||||
import { type PresentationError, mapToPresentationError } from '@/lib/contracts/page-queries/PresentationError';
|
|
||||||
|
|
||||||
export class LeagueProtestDetailPageQuery implements PageQuery<ProtestDetailViewData, { leagueId: string; protestId: string }, PresentationError> {
|
export class LeagueProtestDetailPageQuery implements PageQuery<ProtestDetailViewData, { leagueId: string; protestId: string }, PresentationError> {
|
||||||
async execute(params: { leagueId: string; protestId: string }): Promise<Result<ProtestDetailViewData, PresentationError>> {
|
async execute(params: { leagueId: string; protestId: string }): Promise<Result<ProtestDetailViewData, PresentationError>> {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
|
import { RulebookViewDataBuilder } from '@/lib/builders/view-data/RulebookViewDataBuilder';
|
||||||
import { PageQuery } from '@/lib/contracts/page-queries/PageQuery';
|
import { PageQuery } from '@/lib/contracts/page-queries/PageQuery';
|
||||||
|
import { type PresentationError, mapToPresentationError } from '@/lib/contracts/page-queries/PresentationError';
|
||||||
import { Result } from '@/lib/contracts/Result';
|
import { Result } from '@/lib/contracts/Result';
|
||||||
import { LeagueRulebookService } from '@/lib/services/leagues/LeagueRulebookService';
|
import { LeagueRulebookService } from '@/lib/services/leagues/LeagueRulebookService';
|
||||||
import { RulebookViewDataBuilder } from '@/lib/builders/view-data/RulebookViewDataBuilder';
|
import { RulebookViewData } from '@/lib/view-data/RulebookViewData';
|
||||||
import { RulebookViewData } from '@/lib/view-data/leagues/RulebookViewData';
|
|
||||||
import { type PresentationError, mapToPresentationError } from '@/lib/contracts/page-queries/PresentationError';
|
|
||||||
|
|
||||||
export class LeagueRulebookPageQuery implements PageQuery<RulebookViewData, string, PresentationError> {
|
export class LeagueRulebookPageQuery implements PageQuery<RulebookViewData, string, PresentationError> {
|
||||||
async execute(leagueId: string): Promise<Result<RulebookViewData, PresentationError>> {
|
async execute(leagueId: string): Promise<Result<RulebookViewData, PresentationError>> {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
|
import { LeagueSettingsViewDataBuilder } from '@/lib/builders/view-data/LeagueSettingsViewDataBuilder';
|
||||||
import { PageQuery } from '@/lib/contracts/page-queries/PageQuery';
|
import { PageQuery } from '@/lib/contracts/page-queries/PageQuery';
|
||||||
|
import { type PresentationError, mapToPresentationError } from '@/lib/contracts/page-queries/PresentationError';
|
||||||
import { Result } from '@/lib/contracts/Result';
|
import { Result } from '@/lib/contracts/Result';
|
||||||
import { LeagueSettingsService } from '@/lib/services/leagues/LeagueSettingsService';
|
import { LeagueSettingsService } from '@/lib/services/leagues/LeagueSettingsService';
|
||||||
import { LeagueSettingsViewDataBuilder } from '@/lib/builders/view-data/LeagueSettingsViewDataBuilder';
|
import { LeagueSettingsViewData } from '@/lib/view-data/LeagueSettingsViewData';
|
||||||
import { LeagueSettingsViewData } from '@/lib/view-data/leagues/LeagueSettingsViewData';
|
|
||||||
import { type PresentationError, mapToPresentationError } from '@/lib/contracts/page-queries/PresentationError';
|
|
||||||
|
|
||||||
export class LeagueSettingsPageQuery implements PageQuery<LeagueSettingsViewData, string, PresentationError> {
|
export class LeagueSettingsPageQuery implements PageQuery<LeagueSettingsViewData, string, PresentationError> {
|
||||||
async execute(leagueId: string): Promise<Result<LeagueSettingsViewData, PresentationError>> {
|
async execute(leagueId: string): Promise<Result<LeagueSettingsViewData, PresentationError>> {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
|
import { LeagueSponsorshipsViewDataBuilder } from '@/lib/builders/view-data/LeagueSponsorshipsViewDataBuilder';
|
||||||
import { PageQuery } from '@/lib/contracts/page-queries/PageQuery';
|
import { PageQuery } from '@/lib/contracts/page-queries/PageQuery';
|
||||||
|
import { type PresentationError, mapToPresentationError } from '@/lib/contracts/page-queries/PresentationError';
|
||||||
import { Result } from '@/lib/contracts/Result';
|
import { Result } from '@/lib/contracts/Result';
|
||||||
import { LeagueSponsorshipsService } from '@/lib/services/leagues/LeagueSponsorshipsService';
|
import { LeagueSponsorshipsService } from '@/lib/services/leagues/LeagueSponsorshipsService';
|
||||||
import { LeagueSponsorshipsViewDataBuilder } from '@/lib/builders/view-data/LeagueSponsorshipsViewDataBuilder';
|
import { LeagueSponsorshipsViewData } from '@/lib/view-data/LeagueSponsorshipsViewData';
|
||||||
import { LeagueSponsorshipsViewData } from '@/lib/view-data/leagues/LeagueSponsorshipsViewData';
|
|
||||||
import { type PresentationError, mapToPresentationError } from '@/lib/contracts/page-queries/PresentationError';
|
|
||||||
|
|
||||||
export class LeagueSponsorshipsPageQuery implements PageQuery<LeagueSponsorshipsViewData, string, PresentationError> {
|
export class LeagueSponsorshipsPageQuery implements PageQuery<LeagueSponsorshipsViewData, string, PresentationError> {
|
||||||
async execute(leagueId: string): Promise<Result<LeagueSponsorshipsViewData, PresentationError>> {
|
async execute(leagueId: string): Promise<Result<LeagueSponsorshipsViewData, PresentationError>> {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
|
import { StewardingViewDataBuilder } from '@/lib/builders/view-data/StewardingViewDataBuilder';
|
||||||
import { Result } from '@/lib/contracts/Result';
|
import { Result } from '@/lib/contracts/Result';
|
||||||
import { PageQuery } from '@/lib/contracts/page-queries/PageQuery';
|
import { PageQuery } from '@/lib/contracts/page-queries/PageQuery';
|
||||||
import { LeagueStewardingService } from '@/lib/services/leagues/LeagueStewardingService';
|
|
||||||
import { StewardingViewDataBuilder } from '@/lib/builders/view-data/StewardingViewDataBuilder';
|
|
||||||
import { StewardingViewData } from '@/lib/view-data/leagues/StewardingViewData';
|
|
||||||
import { type PresentationError, mapToPresentationError } from '@/lib/contracts/page-queries/PresentationError';
|
import { type PresentationError, mapToPresentationError } from '@/lib/contracts/page-queries/PresentationError';
|
||||||
|
import { LeagueStewardingService } from '@/lib/services/leagues/LeagueStewardingService';
|
||||||
|
import { StewardingViewData } from '@/lib/view-data/StewardingViewData';
|
||||||
|
|
||||||
export class LeagueStewardingPageQuery implements PageQuery<StewardingViewData, string, PresentationError> {
|
export class LeagueStewardingPageQuery implements PageQuery<StewardingViewData, string, PresentationError> {
|
||||||
async execute(leagueId: string): Promise<Result<StewardingViewData, PresentationError>> {
|
async execute(leagueId: string): Promise<Result<StewardingViewData, PresentationError>> {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
|
import { LeagueWalletViewDataBuilder } from '@/lib/builders/view-data/LeagueWalletViewDataBuilder';
|
||||||
import { PageQuery } from '@/lib/contracts/page-queries/PageQuery';
|
import { PageQuery } from '@/lib/contracts/page-queries/PageQuery';
|
||||||
|
import { type PresentationError, mapToPresentationError } from '@/lib/contracts/page-queries/PresentationError';
|
||||||
import { Result } from '@/lib/contracts/Result';
|
import { Result } from '@/lib/contracts/Result';
|
||||||
import { LeagueWalletService } from '@/lib/services/leagues/LeagueWalletService';
|
import { LeagueWalletService } from '@/lib/services/leagues/LeagueWalletService';
|
||||||
import { LeagueWalletViewDataBuilder } from '@/lib/builders/view-data/LeagueWalletViewDataBuilder';
|
import { LeagueWalletViewData } from '@/lib/view-data/LeagueWalletViewData';
|
||||||
import { LeagueWalletViewData } from '@/lib/view-data/leagues/LeagueWalletViewData';
|
|
||||||
import { type PresentationError, mapToPresentationError } from '@/lib/contracts/page-queries/PresentationError';
|
|
||||||
|
|
||||||
export class LeagueWalletPageQuery implements PageQuery<LeagueWalletViewData, string, PresentationError> {
|
export class LeagueWalletPageQuery implements PageQuery<LeagueWalletViewData, string, PresentationError> {
|
||||||
async execute(leagueId: string): Promise<Result<LeagueWalletViewData, PresentationError>> {
|
async execute(leagueId: string): Promise<Result<LeagueWalletViewData, PresentationError>> {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
|
import { ForgotPasswordViewDataBuilder } from '@/lib/builders/view-data/ForgotPasswordViewDataBuilder';
|
||||||
import { Result } from '@/lib/contracts/Result';
|
import { Result } from '@/lib/contracts/Result';
|
||||||
import { PageQuery } from '@/lib/contracts/page-queries/PageQuery';
|
import { PageQuery } from '@/lib/contracts/page-queries/PageQuery';
|
||||||
import { ForgotPasswordViewDataBuilder } from '@/lib/builders/view-data/ForgotPasswordViewDataBuilder';
|
|
||||||
import { ForgotPasswordViewData } from '@/lib/builders/view-data/types/ForgotPasswordViewData';
|
|
||||||
import { AuthPageService } from '@/lib/services/auth/AuthPageService';
|
|
||||||
import { SearchParamParser } from '@/lib/routing/search-params/SearchParamParser';
|
import { SearchParamParser } from '@/lib/routing/search-params/SearchParamParser';
|
||||||
|
import { AuthPageService } from '@/lib/services/auth/AuthPageService';
|
||||||
|
import { ForgotPasswordViewData } from '@/lib/view-data/ForgotPasswordViewData';
|
||||||
|
|
||||||
export class ForgotPasswordPageQuery implements PageQuery<ForgotPasswordViewData, URLSearchParams | Record<string, string | string[] | undefined>> {
|
export class ForgotPasswordPageQuery implements PageQuery<ForgotPasswordViewData, URLSearchParams | Record<string, string | string[] | undefined>> {
|
||||||
async execute(searchParams: URLSearchParams | Record<string, string | string[] | undefined>): Promise<Result<ForgotPasswordViewData, string>> {
|
async execute(searchParams: URLSearchParams | Record<string, string | string[] | undefined>): Promise<Result<ForgotPasswordViewData, string>> {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
|
import { LoginViewDataBuilder } from '@/lib/builders/view-data/LoginViewDataBuilder';
|
||||||
import { Result } from '@/lib/contracts/Result';
|
import { Result } from '@/lib/contracts/Result';
|
||||||
import { PageQuery } from '@/lib/contracts/page-queries/PageQuery';
|
import { PageQuery } from '@/lib/contracts/page-queries/PageQuery';
|
||||||
import { LoginViewDataBuilder } from '@/lib/builders/view-data/LoginViewDataBuilder';
|
|
||||||
import { LoginViewData } from '@/lib/builders/view-data/types/LoginViewData';
|
|
||||||
import { AuthPageService } from '@/lib/services/auth/AuthPageService';
|
|
||||||
import { SearchParamParser } from '@/lib/routing/search-params/SearchParamParser';
|
import { SearchParamParser } from '@/lib/routing/search-params/SearchParamParser';
|
||||||
|
import { AuthPageService } from '@/lib/services/auth/AuthPageService';
|
||||||
|
import { LoginViewData } from '@/lib/view-data/LoginViewData';
|
||||||
|
|
||||||
export class LoginPageQuery implements PageQuery<LoginViewData, URLSearchParams | Record<string, string | string[] | undefined>> {
|
export class LoginPageQuery implements PageQuery<LoginViewData, URLSearchParams | Record<string, string | string[] | undefined>> {
|
||||||
async execute(searchParams: URLSearchParams | Record<string, string | string[] | undefined>): Promise<Result<LoginViewData, string>> {
|
async execute(searchParams: URLSearchParams | Record<string, string | string[] | undefined>): Promise<Result<LoginViewData, string>> {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
|
import { ResetPasswordViewDataBuilder } from '@/lib/builders/view-data/ResetPasswordViewDataBuilder';
|
||||||
import { Result } from '@/lib/contracts/Result';
|
import { Result } from '@/lib/contracts/Result';
|
||||||
import { PageQuery } from '@/lib/contracts/page-queries/PageQuery';
|
import { PageQuery } from '@/lib/contracts/page-queries/PageQuery';
|
||||||
import { ResetPasswordViewDataBuilder } from '@/lib/builders/view-data/ResetPasswordViewDataBuilder';
|
|
||||||
import { ResetPasswordViewData } from '@/lib/builders/view-data/types/ResetPasswordViewData';
|
|
||||||
import { AuthPageService } from '@/lib/services/auth/AuthPageService';
|
|
||||||
import { SearchParamParser } from '@/lib/routing/search-params/SearchParamParser';
|
import { SearchParamParser } from '@/lib/routing/search-params/SearchParamParser';
|
||||||
|
import { AuthPageService } from '@/lib/services/auth/AuthPageService';
|
||||||
|
import { ResetPasswordViewData } from '@/lib/view-data/ResetPasswordViewData';
|
||||||
|
|
||||||
export class ResetPasswordPageQuery implements PageQuery<ResetPasswordViewData, URLSearchParams | Record<string, string | string[] | undefined>> {
|
export class ResetPasswordPageQuery implements PageQuery<ResetPasswordViewData, URLSearchParams | Record<string, string | string[] | undefined>> {
|
||||||
async execute(searchParams: URLSearchParams | Record<string, string | string[] | undefined>): Promise<Result<ResetPasswordViewData, string>> {
|
async execute(searchParams: URLSearchParams | Record<string, string | string[] | undefined>): Promise<Result<ResetPasswordViewData, string>> {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { SignupViewDataBuilder } from '@/lib/builders/view-data/SignupViewDataBuilder';
|
import { SignupViewDataBuilder } from '@/lib/builders/view-data/SignupViewDataBuilder';
|
||||||
import { SignupViewData } from '@/lib/builders/view-data/types/SignupViewData';
|
|
||||||
import { Result } from '@/lib/contracts/Result';
|
import { Result } from '@/lib/contracts/Result';
|
||||||
import { PageQuery } from '@/lib/contracts/page-queries/PageQuery';
|
import { PageQuery } from '@/lib/contracts/page-queries/PageQuery';
|
||||||
import { AuthPageService } from '@/lib/services/auth/AuthPageService';
|
|
||||||
import { SearchParamParser } from '@/lib/routing/search-params/SearchParamParser';
|
import { SearchParamParser } from '@/lib/routing/search-params/SearchParamParser';
|
||||||
|
import { AuthPageService } from '@/lib/services/auth/AuthPageService';
|
||||||
|
import { SignupViewData } from '@/lib/view-data/SignupViewData';
|
||||||
|
|
||||||
export class SignupPageQuery implements PageQuery<SignupViewData, URLSearchParams | Record<string, string | string[] | undefined>> {
|
export class SignupPageQuery implements PageQuery<SignupViewData, URLSearchParams | Record<string, string | string[] | undefined>> {
|
||||||
async execute(searchParams: URLSearchParams | Record<string, string | string[] | undefined>): Promise<Result<SignupViewData, string>> {
|
async execute(searchParams: URLSearchParams | Record<string, string | string[] | undefined>): Promise<Result<SignupViewData, string>> {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
|
import { RaceDetailViewDataBuilder } from '@/lib/builders/view-data/RaceDetailViewDataBuilder';
|
||||||
import { Result } from '@/lib/contracts/Result';
|
import { Result } from '@/lib/contracts/Result';
|
||||||
import { PageQuery } from '@/lib/contracts/page-queries/PageQuery';
|
import { PageQuery } from '@/lib/contracts/page-queries/PageQuery';
|
||||||
import { PresentationError, mapToPresentationError } from '@/lib/contracts/page-queries/PresentationError';
|
import { PresentationError, mapToPresentationError } from '@/lib/contracts/page-queries/PresentationError';
|
||||||
import { RaceDetailViewData } from '@/lib/view-data/races/RaceDetailViewData';
|
|
||||||
import { RacesService } from '@/lib/services/races/RacesService';
|
import { RacesService } from '@/lib/services/races/RacesService';
|
||||||
import { RaceDetailViewDataBuilder } from '@/lib/builders/view-data/RaceDetailViewDataBuilder';
|
import { RaceDetailViewData } from '@/lib/view-data/RaceDetailViewData';
|
||||||
|
|
||||||
interface RaceDetailPageQueryParams {
|
interface RaceDetailPageQueryParams {
|
||||||
raceId: string;
|
raceId: string;
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
|
import { RaceResultsViewDataBuilder } from '@/lib/builders/view-data/RaceResultsViewDataBuilder';
|
||||||
import { Result } from '@/lib/contracts/Result';
|
import { Result } from '@/lib/contracts/Result';
|
||||||
import { PageQuery } from '@/lib/contracts/page-queries/PageQuery';
|
import { PageQuery } from '@/lib/contracts/page-queries/PageQuery';
|
||||||
import { PresentationError, mapToPresentationError } from '@/lib/contracts/page-queries/PresentationError';
|
import { PresentationError, mapToPresentationError } from '@/lib/contracts/page-queries/PresentationError';
|
||||||
import { RaceResultsViewData } from '@/lib/view-data/races/RaceResultsViewData';
|
|
||||||
import { RaceResultsService } from '@/lib/services/races/RaceResultsService';
|
import { RaceResultsService } from '@/lib/services/races/RaceResultsService';
|
||||||
import { RaceResultsViewDataBuilder } from '@/lib/builders/view-data/RaceResultsViewDataBuilder';
|
import { RaceResultsViewData } from '@/lib/view-data/RaceResultsViewData';
|
||||||
|
|
||||||
interface RaceResultsPageQueryParams {
|
interface RaceResultsPageQueryParams {
|
||||||
raceId: string;
|
raceId: string;
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
|
import { RaceStewardingViewDataBuilder } from '@/lib/builders/view-data/RaceStewardingViewDataBuilder';
|
||||||
import { Result } from '@/lib/contracts/Result';
|
import { Result } from '@/lib/contracts/Result';
|
||||||
import { PageQuery } from '@/lib/contracts/page-queries/PageQuery';
|
import { PageQuery } from '@/lib/contracts/page-queries/PageQuery';
|
||||||
import { PresentationError, mapToPresentationError } from '@/lib/contracts/page-queries/PresentationError';
|
import { PresentationError, mapToPresentationError } from '@/lib/contracts/page-queries/PresentationError';
|
||||||
import { RaceStewardingViewData } from '@/lib/view-data/races/RaceStewardingViewData';
|
|
||||||
import { RaceStewardingService } from '@/lib/services/races/RaceStewardingService';
|
import { RaceStewardingService } from '@/lib/services/races/RaceStewardingService';
|
||||||
import { RaceStewardingViewDataBuilder } from '@/lib/builders/view-data/RaceStewardingViewDataBuilder';
|
import { RaceStewardingViewData } from '@/lib/view-data/RaceStewardingViewData';
|
||||||
|
|
||||||
interface RaceStewardingPageQueryParams {
|
interface RaceStewardingPageQueryParams {
|
||||||
raceId: string;
|
raceId: string;
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
|
import { ViewData } from '@/lib/contracts/view-data/ViewData';
|
||||||
import { ActionItem } from '@/lib/queries/ActionsPageQuery';
|
import { ActionItem } from '@/lib/queries/ActionsPageQuery';
|
||||||
|
|
||||||
export interface ActionsViewData {
|
|
||||||
|
export interface ActionsViewData extends ViewData {
|
||||||
actions: ActionItem[];
|
actions: ActionItem[];
|
||||||
}
|
}
|
||||||
|
|||||||
14
apps/website/lib/view-data/ActivityItemViewData.ts
Normal file
14
apps/website/lib/view-data/ActivityItemViewData.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import { ViewData } from '../contracts/view-data/ViewData';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ActivityItemViewData
|
||||||
|
*
|
||||||
|
* ViewData for activity item rendering.
|
||||||
|
*/
|
||||||
|
export interface ActivityItemViewData extends ViewData {
|
||||||
|
id: string;
|
||||||
|
type: string;
|
||||||
|
message: string;
|
||||||
|
time: string;
|
||||||
|
impressions?: number;
|
||||||
|
}
|
||||||
@@ -1,10 +1,13 @@
|
|||||||
|
import { ViewData } from '@/lib/contracts/view-data/ViewData';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AdminDashboardViewData
|
* AdminDashboardViewData
|
||||||
*
|
*
|
||||||
* ViewData for AdminDashboardTemplate.
|
* ViewData for AdminDashboardTemplate.
|
||||||
* Template-ready data structure with only primitives.
|
* Template-ready data structure with only primitives.
|
||||||
*/
|
*/
|
||||||
export interface AdminDashboardViewData {
|
|
||||||
|
export interface AdminDashboardViewData extends ViewData {
|
||||||
stats: {
|
stats: {
|
||||||
totalUsers: number;
|
totalUsers: number;
|
||||||
activeUsers: number;
|
activeUsers: number;
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
|
import { ViewData } from '@/lib/contracts/view-data/ViewData';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AdminUsersViewData
|
* AdminUsersViewData
|
||||||
*
|
*
|
||||||
* ViewData for AdminUsersTemplate.
|
* ViewData for AdminUsersTemplate.
|
||||||
* Template-ready data structure with only primitives.
|
* Template-ready data structure with only primitives.
|
||||||
*/
|
*/
|
||||||
export interface AdminUsersViewData {
|
|
||||||
|
export interface AdminUsersViewData extends ViewData {
|
||||||
users: Array<{
|
users: Array<{
|
||||||
id: string;
|
id: string;
|
||||||
email: string;
|
email: string;
|
||||||
|
|||||||
13
apps/website/lib/view-data/AnalyticsDashboardViewData.ts
Normal file
13
apps/website/lib/view-data/AnalyticsDashboardViewData.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import { ViewData } from "../contracts/view-data/ViewData";
|
||||||
|
|
||||||
|
export interface AnalyticsDashboardViewData extends ViewData {
|
||||||
|
metrics: {
|
||||||
|
totalUsers: number;
|
||||||
|
activeUsers: number;
|
||||||
|
totalRaces: number;
|
||||||
|
totalLeagues: number;
|
||||||
|
userEngagementRate: number;
|
||||||
|
formattedEngagementRate: string;
|
||||||
|
activityLevel: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
42
apps/website/lib/view-data/AvailableLeaguesViewData.ts
Normal file
42
apps/website/lib/view-data/AvailableLeaguesViewData.ts
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
import { ViewData } from "../contracts/view-data/ViewData";
|
||||||
|
|
||||||
|
export interface AvailableLeaguesViewData extends ViewData {
|
||||||
|
leagues: AvailableLeagueViewData[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AvailableLeagueViewData {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
game: string;
|
||||||
|
drivers: number;
|
||||||
|
avgViewsPerRace: number;
|
||||||
|
formattedAvgViews: string;
|
||||||
|
mainSponsorSlot: {
|
||||||
|
available: boolean;
|
||||||
|
price: number;
|
||||||
|
};
|
||||||
|
secondarySlots: {
|
||||||
|
available: number;
|
||||||
|
total: number;
|
||||||
|
price: number;
|
||||||
|
};
|
||||||
|
cpm: number;
|
||||||
|
formattedCpm: string;
|
||||||
|
hasAvailableSlots: boolean;
|
||||||
|
rating: number;
|
||||||
|
tier: 'premium' | 'standard' | 'starter';
|
||||||
|
tierConfig: {
|
||||||
|
color: string;
|
||||||
|
bgColor: string;
|
||||||
|
border: string;
|
||||||
|
icon: string;
|
||||||
|
};
|
||||||
|
nextRace?: string;
|
||||||
|
seasonStatus: 'active' | 'upcoming' | 'completed';
|
||||||
|
statusConfig: {
|
||||||
|
color: string;
|
||||||
|
bg: string;
|
||||||
|
label: string;
|
||||||
|
};
|
||||||
|
description: string;
|
||||||
|
}
|
||||||
12
apps/website/lib/view-data/AvatarGenerationViewData.ts
Normal file
12
apps/website/lib/view-data/AvatarGenerationViewData.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { ViewData } from "../contracts/view-data/ViewData";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AvatarGenerationViewData
|
||||||
|
*
|
||||||
|
* ViewData for avatar generation process.
|
||||||
|
*/
|
||||||
|
export interface AvatarGenerationViewData extends ViewData {
|
||||||
|
success: boolean;
|
||||||
|
avatarUrls: string[];
|
||||||
|
errorMessage?: string;
|
||||||
|
}
|
||||||
@@ -1,9 +1,12 @@
|
|||||||
|
import { ViewData } from '@/lib/contracts/view-data/ViewData';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AvatarViewData
|
* AvatarViewData
|
||||||
*
|
*
|
||||||
* ViewData for avatar media rendering.
|
* ViewData for avatar media rendering.
|
||||||
*/
|
*/
|
||||||
export interface AvatarViewData {
|
|
||||||
|
export interface AvatarViewData extends ViewData {
|
||||||
buffer: string; // base64 encoded
|
buffer: string; // base64 encoded
|
||||||
contentType: string;
|
contentType: string;
|
||||||
}
|
}
|
||||||
@@ -1,9 +1,13 @@
|
|||||||
|
import { ViewData } from '@/lib/contracts/view-data/ViewData';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CategoryIconViewData
|
* CategoryIconViewData
|
||||||
*
|
*
|
||||||
* ViewData for category icon media rendering.
|
* ViewData for category icon media rendering.
|
||||||
*/
|
*/
|
||||||
export interface CategoryIconViewData {
|
import { ViewData } from "../contracts/view-data/ViewData";
|
||||||
|
|
||||||
|
export interface CategoryIconViewData extends ViewData {
|
||||||
buffer: string; // base64 encoded
|
buffer: string; // base64 encoded
|
||||||
contentType: string;
|
contentType: string;
|
||||||
}
|
}
|
||||||
14
apps/website/lib/view-data/CreateLeagueViewData.ts
Normal file
14
apps/website/lib/view-data/CreateLeagueViewData.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import { ViewData } from '../contracts/view-data/ViewData';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CreateLeagueViewData
|
||||||
|
*
|
||||||
|
* ViewData for the create league result page.
|
||||||
|
* Contains only raw serializable data, no methods or computed properties
|
||||||
|
*/
|
||||||
|
|
||||||
|
export interface CreateLeagueViewData extends ViewData {
|
||||||
|
leagueId: string;
|
||||||
|
success: boolean;
|
||||||
|
successMessage: string;
|
||||||
|
}
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { ViewData } from '@/lib/contracts/view-data/ViewData';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dashboard ViewData
|
* Dashboard ViewData
|
||||||
*
|
*
|
||||||
@@ -6,7 +8,8 @@
|
|||||||
* for display and ISO string timestamps for JSON serialization.
|
* for display and ISO string timestamps for JSON serialization.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export interface DashboardViewData {
|
|
||||||
|
export interface DashboardViewData extends ViewData {
|
||||||
currentDriver: {
|
currentDriver: {
|
||||||
name: string;
|
name: string;
|
||||||
avatarUrl: string;
|
avatarUrl: string;
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
export interface DriverRankingItem {
|
import { ViewData } from '@/lib/contracts/view-data/ViewData';
|
||||||
|
|
||||||
|
|
||||||
|
export interface DriverRankingItem extends ViewData {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
rating: number;
|
rating: number;
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
|
import { ViewData } from '@/lib/contracts/view-data/ViewData';
|
||||||
import type { DriverRankingItem } from './DriverRankingItem';
|
import type { DriverRankingItem } from './DriverRankingItem';
|
||||||
import type { PodiumDriver } from './PodiumDriver';
|
import type { PodiumDriver } from './PodiumDriver';
|
||||||
|
|
||||||
export interface DriverRankingsViewData {
|
|
||||||
|
export interface DriverRankingsViewData extends ViewData {
|
||||||
drivers: DriverRankingItem[];
|
drivers: DriverRankingItem[];
|
||||||
podium: PodiumDriver[];
|
podium: PodiumDriver[];
|
||||||
searchQuery: string;
|
searchQuery: string;
|
||||||
|
|||||||
18
apps/website/lib/view-data/ForgotPasswordViewData.ts
Normal file
18
apps/website/lib/view-data/ForgotPasswordViewData.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import { ViewData } from '@/lib/contracts/view-data/ViewData';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Forgot Password View Data
|
||||||
|
*
|
||||||
|
* ViewData for the forgot password template.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
export interface ForgotPasswordViewData extends ViewData {
|
||||||
|
returnTo: string;
|
||||||
|
showSuccess: boolean;
|
||||||
|
successMessage?: string;
|
||||||
|
magicLink?: string;
|
||||||
|
formState: any; // Will be managed by client component
|
||||||
|
isSubmitting: boolean;
|
||||||
|
submitError?: string;
|
||||||
|
}
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Health View Data Types
|
* Health View Data Types
|
||||||
*
|
*
|
||||||
@@ -52,7 +53,9 @@ export interface HealthAlert {
|
|||||||
severityColor: string;
|
severityColor: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface HealthViewData {
|
import { ViewData } from "../contracts/view-data/ViewData";
|
||||||
|
|
||||||
|
export interface HealthViewData extends ViewData {
|
||||||
overallStatus: HealthStatus;
|
overallStatus: HealthStatus;
|
||||||
metrics: HealthMetrics;
|
metrics: HealthMetrics;
|
||||||
components: HealthComponent[];
|
components: HealthComponent[];
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
export interface LeaderboardDriverItem {
|
import { ViewData } from '@/lib/contracts/view-data/ViewData';
|
||||||
|
|
||||||
|
|
||||||
|
export interface LeaderboardDriverItem extends ViewData {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
rating: number;
|
rating: number;
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
export interface LeaderboardTeamItem {
|
import { ViewData } from '@/lib/contracts/view-data/ViewData';
|
||||||
|
|
||||||
|
|
||||||
|
export interface LeaderboardTeamItem extends ViewData {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
tag: string;
|
tag: string;
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
|
import { ViewData } from '@/lib/contracts/view-data/ViewData';
|
||||||
import type { LeaderboardDriverItem } from './LeaderboardDriverItem';
|
import type { LeaderboardDriverItem } from './LeaderboardDriverItem';
|
||||||
import type { LeaderboardTeamItem } from './LeaderboardTeamItem';
|
import type { LeaderboardTeamItem } from './LeaderboardTeamItem';
|
||||||
|
|
||||||
export interface LeaderboardsViewData {
|
|
||||||
|
export interface LeaderboardsViewData extends ViewData {
|
||||||
drivers: LeaderboardDriverItem[];
|
drivers: LeaderboardDriverItem[];
|
||||||
teams: LeaderboardTeamItem[];
|
teams: LeaderboardTeamItem[];
|
||||||
}
|
}
|
||||||
@@ -1,17 +1,10 @@
|
|||||||
export interface AdminScheduleRaceData {
|
import { ViewData } from '@/lib/contracts/view-data/ViewData';
|
||||||
|
|
||||||
|
|
||||||
|
export interface AdminScheduleRaceData extends ViewData {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
track: string;
|
track: string;
|
||||||
car: string;
|
car: string;
|
||||||
scheduledAt: string; // ISO string
|
scheduledAt: string; // ISO string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LeagueAdminScheduleViewData {
|
|
||||||
published: boolean;
|
|
||||||
races: AdminScheduleRaceData[];
|
|
||||||
seasons: Array<{
|
|
||||||
seasonId: string;
|
|
||||||
name: string;
|
|
||||||
}>;
|
|
||||||
seasonId: string;
|
|
||||||
}
|
|
||||||
@@ -1,9 +1,12 @@
|
|||||||
|
import { ViewData } from '@/lib/contracts/view-data/ViewData';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* LeagueCoverViewData
|
* LeagueCoverViewData
|
||||||
*
|
*
|
||||||
* ViewData for league cover media rendering.
|
* ViewData for league cover media rendering.
|
||||||
*/
|
*/
|
||||||
export interface LeagueCoverViewData {
|
|
||||||
|
export interface LeagueCoverViewData extends ViewData {
|
||||||
buffer: string; // base64 encoded
|
buffer: string; // base64 encoded
|
||||||
contentType: string;
|
contentType: string;
|
||||||
}
|
}
|
||||||
@@ -87,6 +87,7 @@ export interface RecentResult {
|
|||||||
finishedAt: string;
|
finishedAt: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export interface LeagueDetailViewData extends ViewData {
|
export interface LeagueDetailViewData extends ViewData {
|
||||||
// Basic info
|
// Basic info
|
||||||
leagueId: string;
|
leagueId: string;
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
|
import { ViewData } from '@/lib/contracts/view-data/ViewData';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* LeagueLogoViewData
|
* LeagueLogoViewData
|
||||||
*
|
*
|
||||||
* ViewData for league logo media rendering.
|
* ViewData for league logoViewData extends ViewData {dering.
|
||||||
*/
|
*/
|
||||||
export interface LeagueLogoViewData {
|
|
||||||
|
export interface LeagueLogoViewData extends ViewData {
|
||||||
buffer: string; // base64 encoded
|
buffer: string; // base64 encoded
|
||||||
contentType: string;
|
contentType: string;
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { ViewData } from '@/lib/contracts/view-data/ViewData';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* LeagueRosterAdminViewData - Pure ViewData for RosterAdminPage
|
* LeagueRosterAdminViewData - Pure ViewData for RosterAdminPage
|
||||||
* Contains only raw serializable data, no methods or computed properties
|
* Contains only raw serializable data, no methods or computed properties
|
||||||
@@ -25,7 +27,8 @@ export interface JoinRequestData {
|
|||||||
message?: string;
|
message?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LeagueRosterAdminViewData {
|
|
||||||
|
export interface LeagueRosterAdminViewData extends ViewData {
|
||||||
leagueId: string;
|
leagueId: string;
|
||||||
members: RosterMemberData[];
|
members: RosterMemberData[];
|
||||||
joinRequests: JoinRequestData[];
|
joinRequests: JoinRequestData[];
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
export interface RulebookScoringConfig {
|
import { ViewData } from '@/lib/contracts/view-data/ViewData';
|
||||||
|
|
||||||
|
|
||||||
|
export interface RulebookScoringConfig extends ViewData {
|
||||||
scoringPresetName: string | null;
|
scoringPresetName: string | null;
|
||||||
gameName: string;
|
gameName: string;
|
||||||
championships: Array<{
|
championships: Array<{
|
||||||
@@ -12,9 +15,4 @@ export interface RulebookScoringConfig {
|
|||||||
bonusSummary: string[];
|
bonusSummary: string[];
|
||||||
}>;
|
}>;
|
||||||
dropPolicySummary: string;
|
dropPolicySummary: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LeagueRulebookViewData {
|
|
||||||
scoringConfig: RulebookScoringConfig | null;
|
|
||||||
positionPoints: Array<{ position: number; points: number }>;
|
|
||||||
}
|
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { ViewData } from '@/lib/contracts/view-data/ViewData';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* LeagueScheduleViewData - Pure ViewData for LeagueScheduleTemplate
|
* LeagueScheduleViewData - Pure ViewData for LeagueScheduleTemplate
|
||||||
* Contains only raw serializable data, no methods or computed properties
|
* Contains only raw serializable data, no methods or computed properties
|
||||||
@@ -12,7 +14,8 @@ export interface ScheduleRaceData {
|
|||||||
status: string;
|
status: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LeagueScheduleViewData {
|
|
||||||
|
export interface LeagueScheduleViewData extends ViewData {
|
||||||
leagueId: string;
|
leagueId: string;
|
||||||
races: ScheduleRaceData[];
|
races: ScheduleRaceData[];
|
||||||
seasons: Array<{
|
seasons: Array<{
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
export interface LeagueSettingsViewData {
|
import { ViewData } from "../contracts/view-data/ViewData";
|
||||||
|
|
||||||
|
|
||||||
|
export interface LeagueSettingsViewData extends ViewData {
|
||||||
leagueId: string;
|
leagueId: string;
|
||||||
league: {
|
league: {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -1,4 +1,7 @@
|
|||||||
export interface LeagueSponsorshipsViewData {
|
import { ViewData } from '@/lib/contracts/view-data/ViewData';
|
||||||
|
|
||||||
|
|
||||||
|
export interface LeagueSponsorshipsViewData extends ViewData {
|
||||||
leagueId: string;
|
leagueId: string;
|
||||||
activeTab: 'overview' | 'editor';
|
activeTab: 'overview' | 'editor';
|
||||||
onTabChange: (tab: 'overview' | 'editor') => void;
|
onTabChange: (tab: 'overview' | 'editor') => void;
|
||||||
@@ -1,25 +1,4 @@
|
|||||||
/**
|
|
||||||
* LeagueStandingsViewData - Pure ViewData for LeagueStandingsTemplate
|
|
||||||
* Contains only raw serializable data, no methods or computed properties
|
|
||||||
*/
|
|
||||||
|
|
||||||
export interface StandingEntryData {
|
|
||||||
driverId: string;
|
|
||||||
position: number;
|
|
||||||
totalPoints: number;
|
|
||||||
racesFinished: number;
|
|
||||||
racesStarted: number;
|
|
||||||
avgFinish: number | null;
|
|
||||||
penaltyPoints: number;
|
|
||||||
bonusPoints: number;
|
|
||||||
teamName?: string;
|
|
||||||
// New fields from Phase 3
|
|
||||||
positionChange: number;
|
|
||||||
lastRacePoints: number;
|
|
||||||
droppedRaceIds: string[];
|
|
||||||
wins: number;
|
|
||||||
podiums: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface DriverData {
|
export interface DriverData {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -36,15 +15,4 @@ export interface LeagueMembershipData {
|
|||||||
role: 'owner' | 'admin' | 'steward' | 'member';
|
role: 'owner' | 'admin' | 'steward' | 'member';
|
||||||
joinedAt: string;
|
joinedAt: string;
|
||||||
status: 'active' | 'pending' | 'banned';
|
status: 'active' | 'pending' | 'banned';
|
||||||
}
|
|
||||||
|
|
||||||
export interface LeagueStandingsViewData {
|
|
||||||
standings: StandingEntryData[];
|
|
||||||
drivers: DriverData[];
|
|
||||||
memberships: LeagueMembershipData[];
|
|
||||||
leagueId: string;
|
|
||||||
currentDriverId: string | null;
|
|
||||||
isAdmin: boolean;
|
|
||||||
// New fields for team standings toggle
|
|
||||||
isTeamChampionship?: boolean;
|
|
||||||
}
|
}
|
||||||
16
apps/website/lib/view-data/LeagueWalletViewData.ts
Normal file
16
apps/website/lib/view-data/LeagueWalletViewData.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { ViewData } from "../contracts/view-data/ViewData";
|
||||||
|
|
||||||
|
|
||||||
|
export interface LeagueWalletTransactionViewData extends ViewData {
|
||||||
|
id: string;
|
||||||
|
type: 'deposit' | 'withdrawal' | 'sponsorship' | 'prize';
|
||||||
|
amount: number;
|
||||||
|
formattedAmount: string;
|
||||||
|
amountColor: string;
|
||||||
|
description: string;
|
||||||
|
createdAt: string;
|
||||||
|
formattedDate: string;
|
||||||
|
status: 'completed' | 'pending' | 'failed';
|
||||||
|
statusColor: string;
|
||||||
|
typeColor: string;
|
||||||
|
}
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { ViewData } from '@/lib/contracts/view-data/ViewData';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Leagues ViewData
|
* Leagues ViewData
|
||||||
*
|
*
|
||||||
@@ -6,7 +8,8 @@
|
|||||||
* for display and ISO string timestamps for JSON serialization.
|
* for display and ISO string timestamps for JSON serialization.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export interface LeaguesViewData {
|
|
||||||
|
export interface LeaguesViewData extends ViewData {
|
||||||
leagues: Array<{
|
leagues: Array<{
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
|
|||||||
20
apps/website/lib/view-data/LoginViewData.ts
Normal file
20
apps/website/lib/view-data/LoginViewData.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
/**
|
||||||
|
* Login View Data
|
||||||
|
*
|
||||||
|
* ViewData for the login template.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { FormState } from '../builders/view-data/types/FormState';
|
||||||
|
|
||||||
|
import { ViewData } from '@/lib/contracts/view-data/ViewData';
|
||||||
|
|
||||||
|
|
||||||
|
export interface LoginViewData extends ViewData {
|
||||||
|
returnTo: string;
|
||||||
|
hasInsufficientPermissions: boolean;
|
||||||
|
showPassword: boolean;
|
||||||
|
showErrorDetails: boolean;
|
||||||
|
formState: FormState;
|
||||||
|
isSubmitting: boolean;
|
||||||
|
submitError?: string;
|
||||||
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
import { MediaAsset } from '@/components/media/MediaGallery';
|
import { MediaAsset } from '@/components/media/MediaGallery';
|
||||||
|
import { ViewData } from '../contracts/view-data/ViewData';
|
||||||
|
|
||||||
export interface MediaViewData {
|
|
||||||
|
export interface MediaViewData extends ViewData {
|
||||||
assets: MediaAsset[];
|
assets: MediaAsset[];
|
||||||
categories: { label: string; value: string }[];
|
categories: { label: string; value: string }[];
|
||||||
title: string;
|
title: string;
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
export interface OnboardingPageViewData {
|
import { ViewData } from "../contracts/view-data/ViewData";
|
||||||
|
|
||||||
|
|
||||||
|
export interface OnboardingPageViewData extends ViewData {
|
||||||
isAlreadyOnboarded: boolean;
|
isAlreadyOnboarded: boolean;
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,7 @@
|
|||||||
export interface PodiumDriver {
|
import { ViewData } from '@/lib/contracts/view-data/ViewData';
|
||||||
|
|
||||||
|
|
||||||
|
export interface PodiumDriverViewData extends ViewData {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
rating: number;
|
rating: number;
|
||||||
@@ -1,3 +1,6 @@
|
|||||||
export interface ProfileLayoutViewData {
|
import { ViewData } from "../contracts/view-data/ViewData";
|
||||||
|
|
||||||
|
|
||||||
|
export interface ProfileLayoutViewData extends ViewData {
|
||||||
// Empty for now
|
// Empty for now
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,14 +3,18 @@
|
|||||||
* Pure, JSON-serializable data structure for Template rendering
|
* Pure, JSON-serializable data structure for Template rendering
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export interface ProfileLeaguesLeagueViewData {
|
import { ViewData } from "../contracts/view-data/ViewData";
|
||||||
|
|
||||||
|
|
||||||
|
export interface ProfileLeaguesLeagueViewData extends ViewData {
|
||||||
leagueId: string;
|
leagueId: string;
|
||||||
name: string;
|
name: string;
|
||||||
description: string;
|
description: string;
|
||||||
membershipRole: 'owner' | 'admin' | 'steward' | 'member';
|
membershipRole: 'owner' | 'admin' | 'steward' | 'member';
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ProfileLeaguesViewData {
|
|
||||||
|
export interface ProfileLeaguesViewData extends ViewData {
|
||||||
ownedLeagues: ProfileLeaguesLeagueViewData[];
|
ownedLeagues: ProfileLeaguesLeagueViewData[];
|
||||||
memberLeagues: ProfileLeaguesLeagueViewData[];
|
memberLeagues: ProfileLeaguesLeagueViewData[];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
export interface ProfileLiveryViewData {
|
import { ViewData } from "../contracts/view-data/ViewData";
|
||||||
|
|
||||||
|
|
||||||
|
export interface ProfileLiveryViewData extends ViewData {
|
||||||
id: string;
|
id: string;
|
||||||
carId: string;
|
carId: string;
|
||||||
carName: string;
|
carName: string;
|
||||||
@@ -7,6 +10,7 @@ export interface ProfileLiveryViewData {
|
|||||||
isValidated: boolean;
|
isValidated: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ProfileLiveriesViewData {
|
|
||||||
|
export interface ProfileLiveriesViewData extends ViewData {
|
||||||
liveries: ProfileLiveryViewData[];
|
liveries: ProfileLiveryViewData[];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
export interface ProfileViewData {
|
import { ViewData } from "../contracts/view-data/ViewData";
|
||||||
|
|
||||||
|
|
||||||
|
export interface ProfileViewData extends ViewData {
|
||||||
driver: {
|
driver: {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
export interface ProtestDetailViewData {
|
import { ViewData } from "../contracts/view-data/ViewData";
|
||||||
|
|
||||||
|
|
||||||
|
export interface ProtestDetailViewData extends ViewData {
|
||||||
protestId: string;
|
protestId: string;
|
||||||
leagueId: string;
|
leagueId: string;
|
||||||
status: string;
|
status: string;
|
||||||
@@ -5,6 +5,8 @@
|
|||||||
* JSON-serializable, template-ready data structure.
|
* JSON-serializable, template-ready data structure.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { ViewData } from "../contracts/view-data/ViewData";
|
||||||
|
|
||||||
export interface RaceDetailEntry {
|
export interface RaceDetailEntry {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
@@ -48,7 +50,8 @@ export interface RaceDetailRegistration {
|
|||||||
canRegister: boolean;
|
canRegister: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RaceDetailViewData {
|
|
||||||
|
export interface RaceDetailViewData extends ViewData {
|
||||||
race: RaceDetailRace;
|
race: RaceDetailRace;
|
||||||
league?: RaceDetailLeague;
|
league?: RaceDetailLeague;
|
||||||
entryList: RaceDetailEntry[];
|
entryList: RaceDetailEntry[];
|
||||||
@@ -5,6 +5,8 @@
|
|||||||
* JSON-serializable, template-ready data structure.
|
* JSON-serializable, template-ready data structure.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { ViewData } from "../contracts/view-data/ViewData";
|
||||||
|
|
||||||
export interface RaceResultsResult {
|
export interface RaceResultsResult {
|
||||||
position: number;
|
position: number;
|
||||||
driverId: string;
|
driverId: string;
|
||||||
@@ -29,7 +31,8 @@ export interface RaceResultsPenalty {
|
|||||||
notes?: string;
|
notes?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RaceResultsViewData {
|
|
||||||
|
export interface RaceResultsViewData extends ViewData {
|
||||||
raceTrack?: string;
|
raceTrack?: string;
|
||||||
raceScheduledAt?: string;
|
raceScheduledAt?: string;
|
||||||
totalDrivers?: number;
|
totalDrivers?: number;
|
||||||
@@ -5,6 +5,8 @@
|
|||||||
* JSON-serializable, template-ready data structure.
|
* JSON-serializable, template-ready data structure.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { ViewData } from "../contracts/view-data/ViewData";
|
||||||
|
|
||||||
export interface Protest {
|
export interface Protest {
|
||||||
id: string;
|
id: string;
|
||||||
protestingDriverId: string;
|
protestingDriverId: string;
|
||||||
@@ -33,7 +35,8 @@ export interface Driver {
|
|||||||
name: string;
|
name: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RaceStewardingViewData {
|
|
||||||
|
export interface RaceStewardingViewData extends ViewData {
|
||||||
race?: {
|
race?: {
|
||||||
id: string;
|
id: string;
|
||||||
track: string;
|
track: string;
|
||||||
@@ -1,4 +1,7 @@
|
|||||||
export interface RaceViewData {
|
import { ViewData } from "../contracts/view-data/ViewData";
|
||||||
|
|
||||||
|
|
||||||
|
export interface RaceViewData extends ViewData {
|
||||||
id: string;
|
id: string;
|
||||||
track: string;
|
track: string;
|
||||||
car: string;
|
car: string;
|
||||||
@@ -19,7 +22,8 @@ export interface RaceViewData {
|
|||||||
isPast: boolean;
|
isPast: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RacesViewData {
|
|
||||||
|
export interface RacesViewData extends ViewData {
|
||||||
races: RaceViewData[];
|
races: RaceViewData[];
|
||||||
totalCount: number;
|
totalCount: number;
|
||||||
scheduledCount: number;
|
scheduledCount: number;
|
||||||
|
|||||||
18
apps/website/lib/view-data/ResetPasswordViewData.ts
Normal file
18
apps/website/lib/view-data/ResetPasswordViewData.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
/**
|
||||||
|
* Reset Password View Data
|
||||||
|
*
|
||||||
|
* ViewData for the reset password template.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { ViewData } from "../contracts/view-data/ViewData";
|
||||||
|
|
||||||
|
|
||||||
|
export interface ResetPasswordViewData extends ViewData {
|
||||||
|
token: string;
|
||||||
|
returnTo: string;
|
||||||
|
showSuccess: boolean;
|
||||||
|
successMessage?: string;
|
||||||
|
formState: any; // Will be managed by client component
|
||||||
|
isSubmitting: boolean;
|
||||||
|
submitError?: string;
|
||||||
|
}
|
||||||
@@ -1,4 +1,7 @@
|
|||||||
export interface RulebookViewData {
|
import { ViewData } from "../contracts/view-data/ViewData";
|
||||||
|
|
||||||
|
|
||||||
|
export interface RulebookViewData extends ViewData {
|
||||||
leagueId: string;
|
leagueId: string;
|
||||||
gameName: string;
|
gameName: string;
|
||||||
scoringPresetName: string;
|
scoringPresetName: string;
|
||||||
15
apps/website/lib/view-data/SignupViewData.ts
Normal file
15
apps/website/lib/view-data/SignupViewData.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
/**
|
||||||
|
* Signup View Data
|
||||||
|
*
|
||||||
|
* ViewData for the signup template.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { ViewData } from "../contracts/view-data/ViewData";
|
||||||
|
|
||||||
|
|
||||||
|
export interface SignupViewData extends ViewData {
|
||||||
|
returnTo: string;
|
||||||
|
formState: any; // Will be managed by client component
|
||||||
|
isSubmitting: boolean;
|
||||||
|
submitError?: string;
|
||||||
|
}
|
||||||
@@ -1,4 +1,7 @@
|
|||||||
export interface SponsorDashboardViewData {
|
import { ViewData } from "../contracts/view-data/ViewData";
|
||||||
|
|
||||||
|
|
||||||
|
export interface SponsorDashboardViewData extends ViewData {
|
||||||
sponsorName: string;
|
sponsorName: string;
|
||||||
totalImpressions: string;
|
totalImpressions: string;
|
||||||
totalInvestment: string;
|
totalInvestment: string;
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
|
import { ViewData } from "../contracts/view-data/ViewData";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SponsorLogoViewData
|
* SponsorLogoViewData
|
||||||
*
|
*
|
||||||
* ViewData for sponsor logo media rendering.
|
* ViewData for sponsor logo media rendering.
|
||||||
*/
|
*/
|
||||||
export interface SponsorLogoViewData {
|
|
||||||
|
export interface SponsorLogoViewData extends ViewData {
|
||||||
buffer: string; // base64 encoded
|
buffer: string; // base64 encoded
|
||||||
contentType: string;
|
contentType: string;
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,7 @@
|
|||||||
export interface StewardingViewData {
|
import { ViewData } from "../contracts/view-data/ViewData";
|
||||||
|
|
||||||
|
|
||||||
|
export interface StewardingViewData extends ViewData {
|
||||||
leagueId: string;
|
leagueId: string;
|
||||||
totalPending: number;
|
totalPending: number;
|
||||||
totalResolved: number;
|
totalResolved: number;
|
||||||
@@ -3,6 +3,8 @@
|
|||||||
* Contains only raw serializable data, no methods or computed properties
|
* Contains only raw serializable data, no methods or computed properties
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { ViewData } from "../contracts/view-data/ViewData";
|
||||||
|
|
||||||
export interface SponsorMetric {
|
export interface SponsorMetric {
|
||||||
icon: string; // Icon name (e.g. 'users', 'zap', 'calendar')
|
icon: string; // Icon name (e.g. 'users', 'zap', 'calendar')
|
||||||
label: string;
|
label: string;
|
||||||
@@ -51,7 +53,8 @@ export interface TeamTab {
|
|||||||
visible: boolean;
|
visible: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TeamDetailViewData {
|
|
||||||
|
export interface TeamDetailViewData extends ViewData {
|
||||||
team: TeamDetailData;
|
team: TeamDetailData;
|
||||||
memberships: TeamMemberData[];
|
memberships: TeamMemberData[];
|
||||||
currentDriverId: string;
|
currentDriverId: string;
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
|
import { ViewData } from '../contracts/view-data/ViewData';
|
||||||
import type { TeamSummaryViewModel } from '../view-models/TeamSummaryViewModel';
|
import type { TeamSummaryViewModel } from '../view-models/TeamSummaryViewModel';
|
||||||
|
|
||||||
export type SkillLevel = 'pro' | 'advanced' | 'intermediate' | 'beginner';
|
export type SkillLevel = 'pro' | 'advanced' | 'intermediate' | 'beginner';
|
||||||
export type SortBy = 'rating' | 'wins' | 'winRate' | 'races';
|
export type SortBy = 'rating' | 'wins' | 'winRate' | 'races';
|
||||||
|
|
||||||
export interface TeamLeaderboardViewData {
|
|
||||||
|
export interface TeamLeaderboardViewData extends ViewData {
|
||||||
teams: TeamSummaryViewModel[];
|
teams: TeamSummaryViewModel[];
|
||||||
searchQuery: string;
|
searchQuery: string;
|
||||||
filterLevel: SkillLevel | 'all';
|
filterLevel: SkillLevel | 'all';
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
|
import { ViewData } from "../contracts/view-data/ViewData";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TeamLogoViewData
|
* TeamLogoViewData
|
||||||
*
|
*
|
||||||
* ViewData for team logo media rendering.
|
* ViewData for team logo media rendering.
|
||||||
*/
|
*/
|
||||||
export interface TeamLogoViewData {
|
|
||||||
|
export interface TeamLogoViewData extends ViewData {
|
||||||
buffer: string; // base64 encoded
|
buffer: string; // base64 encoded
|
||||||
contentType: string;
|
contentType: string;
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
|
import { ViewData } from '../contracts/view-data/ViewData';
|
||||||
import type { LeaderboardTeamItem } from './LeaderboardTeamItem';
|
import type { LeaderboardTeamItem } from './LeaderboardTeamItem';
|
||||||
|
|
||||||
export interface TeamRankingsViewData {
|
|
||||||
|
export interface TeamRankingsViewData extends ViewData {
|
||||||
teams: LeaderboardTeamItem[];
|
teams: LeaderboardTeamItem[];
|
||||||
podium: LeaderboardTeamItem[];
|
podium: LeaderboardTeamItem[];
|
||||||
recruitingCount: number;
|
recruitingCount: number;
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ export interface TeamSummaryData {
|
|||||||
countryCode?: string;
|
countryCode?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export interface TeamsViewData extends ViewData {
|
export interface TeamsViewData extends ViewData {
|
||||||
teams: TeamSummaryData[];
|
teams: TeamSummaryData[];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
|
import { ViewData } from "../contracts/view-data/ViewData";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* TrackImageViewData
|
* TrackImageViewData
|
||||||
*
|
*
|
||||||
* ViewData for track image media rendering.
|
* ViewData for track image media rendering.
|
||||||
*/
|
*/
|
||||||
export interface TrackImageViewData {
|
|
||||||
|
export interface TrackImageViewData extends ViewData {
|
||||||
buffer: string; // base64 encoded
|
buffer: string; // base64 encoded
|
||||||
contentType: string;
|
contentType: string;
|
||||||
}
|
}
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
export interface LeagueScheduleViewData {
|
|
||||||
leagueId: string;
|
|
||||||
races: Array<{
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
scheduledAt: string; // ISO string
|
|
||||||
track?: string;
|
|
||||||
car?: string;
|
|
||||||
sessionType?: string;
|
|
||||||
isPast: boolean;
|
|
||||||
isUpcoming: boolean;
|
|
||||||
status: 'scheduled' | 'completed';
|
|
||||||
strengthOfField?: number;
|
|
||||||
// Registration info
|
|
||||||
isUserRegistered?: boolean;
|
|
||||||
canRegister?: boolean;
|
|
||||||
// Admin info
|
|
||||||
canEdit?: boolean;
|
|
||||||
canReschedule?: boolean;
|
|
||||||
}>;
|
|
||||||
// User permissions
|
|
||||||
currentDriverId?: string;
|
|
||||||
isAdmin: boolean;
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
export interface LeagueWalletTransactionViewData {
|
|
||||||
id: string;
|
|
||||||
type: 'deposit' | 'withdrawal' | 'sponsorship' | 'prize';
|
|
||||||
amount: number;
|
|
||||||
formattedAmount: string;
|
|
||||||
amountColor: string;
|
|
||||||
description: string;
|
|
||||||
createdAt: string;
|
|
||||||
formattedDate: string;
|
|
||||||
status: 'completed' | 'pending' | 'failed';
|
|
||||||
statusColor: string;
|
|
||||||
typeColor: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface LeagueWalletViewData {
|
|
||||||
leagueId: string;
|
|
||||||
balance: number;
|
|
||||||
formattedBalance: string;
|
|
||||||
totalRevenue: number;
|
|
||||||
formattedTotalRevenue: string;
|
|
||||||
totalFees: number;
|
|
||||||
formattedTotalFees: string;
|
|
||||||
pendingPayouts: number;
|
|
||||||
formattedPendingPayouts: string;
|
|
||||||
currency: string;
|
|
||||||
transactions: LeagueWalletTransactionViewData[];
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
import React from 'react';
|
|
||||||
import { ErrorScreen } from '@/components/errors/ErrorScreen';
|
import { ErrorScreen } from '@/components/errors/ErrorScreen';
|
||||||
|
|
||||||
export interface FatalErrorViewData {
|
export interface FatalErrorViewData extends ViewData {
|
||||||
error: Error & { digest?: string };
|
error: Error & { digest?: string };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,16 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
|
import { CtaSection } from '@/components/home/CtaSection';
|
||||||
import { Hero } from '@/components/home/Hero';
|
import { Hero } from '@/components/home/Hero';
|
||||||
import { TelemetryStrip } from '@/components/home/TelemetryStrip';
|
|
||||||
import { ValuePillars } from '@/components/home/ValuePillars';
|
|
||||||
import { StewardingPreview } from '@/components/home/StewardingPreview';
|
|
||||||
import { LeagueIdentityPreview } from '@/components/home/LeagueIdentityPreview';
|
import { LeagueIdentityPreview } from '@/components/home/LeagueIdentityPreview';
|
||||||
import { MigrationSection } from '@/components/home/MigrationSection';
|
import { MigrationSection } from '@/components/home/MigrationSection';
|
||||||
import { CtaSection } from '@/components/home/CtaSection';
|
import { StewardingPreview } from '@/components/home/StewardingPreview';
|
||||||
|
import { TelemetryStrip } from '@/components/home/TelemetryStrip';
|
||||||
|
import { ValuePillars } from '@/components/home/ValuePillars';
|
||||||
|
import { ViewData } from '@/lib/contracts/view-data/ViewData';
|
||||||
import { Stack } from '@/ui/Stack';
|
import { Stack } from '@/ui/Stack';
|
||||||
|
|
||||||
export interface HomeViewData {
|
export interface HomeViewData extends ViewData {
|
||||||
isAlpha: boolean;
|
isAlpha: boolean;
|
||||||
upcomingRaces: Array<{
|
upcomingRaces: Array<{
|
||||||
id: string;
|
id: string;
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import type { LeagueSettingsViewData } from '@/lib/view-data/leagues/LeagueSettingsViewData';
|
import type { LeagueSettingsViewData } from '@/lib/view-data/LeagueSettingsViewData';
|
||||||
import { Box } from '@/ui/Box';
|
import { Box } from '@/ui/Box';
|
||||||
import { Heading } from '@/ui/Heading';
|
|
||||||
import { Icon } from '@/ui/Icon';
|
|
||||||
import { Grid } from '@/ui/Grid';
|
import { Grid } from '@/ui/Grid';
|
||||||
import { GridItem } from '@/ui/GridItem';
|
import { GridItem } from '@/ui/GridItem';
|
||||||
|
import { Heading } from '@/ui/Heading';
|
||||||
|
import { Icon } from '@/ui/Icon';
|
||||||
import { Stack } from '@/ui/Stack';
|
import { Stack } from '@/ui/Stack';
|
||||||
import { Surface } from '@/ui/Surface';
|
import { Surface } from '@/ui/Surface';
|
||||||
import { Text } from '@/ui/Text';
|
import { Text } from '@/ui/Text';
|
||||||
|
|||||||
@@ -3,12 +3,12 @@
|
|||||||
import { LeagueDecalPlacementEditor } from '@/components/leagues/LeagueDecalPlacementEditor';
|
import { LeagueDecalPlacementEditor } from '@/components/leagues/LeagueDecalPlacementEditor';
|
||||||
import { SponsorshipRequestCard } from '@/components/leagues/SponsorshipRequestCard';
|
import { SponsorshipRequestCard } from '@/components/leagues/SponsorshipRequestCard';
|
||||||
import { SponsorshipSlotCard } from '@/components/leagues/SponsorshipSlotCard';
|
import { SponsorshipSlotCard } from '@/components/leagues/SponsorshipSlotCard';
|
||||||
import type { LeagueSponsorshipsViewData } from '@/lib/view-data/leagues/LeagueSponsorshipsViewData';
|
import type { LeagueSponsorshipsViewData } from '@/lib/view-data/LeagueSponsorshipsViewData';
|
||||||
import { Box } from '@/ui/Box';
|
import { Box } from '@/ui/Box';
|
||||||
import { Card } from '@/ui/Card';
|
import { Card } from '@/ui/Card';
|
||||||
|
import { Grid } from '@/ui/Grid';
|
||||||
import { Heading } from '@/ui/Heading';
|
import { Heading } from '@/ui/Heading';
|
||||||
import { Icon } from '@/ui/Icon';
|
import { Icon } from '@/ui/Icon';
|
||||||
import { Grid } from '@/ui/Grid';
|
|
||||||
import { Stack } from '@/ui/Stack';
|
import { Stack } from '@/ui/Stack';
|
||||||
import { Surface } from '@/ui/Surface';
|
import { Surface } from '@/ui/Surface';
|
||||||
import { Text } from '@/ui/Text';
|
import { Text } from '@/ui/Text';
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { WalletSummaryPanel } from '@/components/leagues/WalletSummaryPanel';
|
import { WalletSummaryPanel } from '@/components/leagues/WalletSummaryPanel';
|
||||||
import type { LeagueWalletViewData } from '@/lib/view-data/leagues/LeagueWalletViewData';
|
import { TemplateProps } from '@/lib/contracts/components/ComponentContracts';
|
||||||
|
import type { LeagueWalletViewData } from '@/lib/view-data/LeagueWalletViewData';
|
||||||
import { Box } from '@/ui/Box';
|
import { Box } from '@/ui/Box';
|
||||||
import { Button } from '@/ui/Button';
|
import { Button } from '@/ui/Button';
|
||||||
import { Container } from '@/ui/Container';
|
import { Container } from '@/ui/Container';
|
||||||
@@ -10,7 +11,6 @@ import { Icon } from '@/ui/Icon';
|
|||||||
import { Stack } from '@/ui/Stack';
|
import { Stack } from '@/ui/Stack';
|
||||||
import { Text } from '@/ui/Text';
|
import { Text } from '@/ui/Text';
|
||||||
import { Download } from 'lucide-react';
|
import { Download } from 'lucide-react';
|
||||||
import { TemplateProps } from '@/lib/contracts/components/ComponentContracts';
|
|
||||||
|
|
||||||
interface LeagueWalletTemplateProps extends TemplateProps<LeagueWalletViewData> {
|
interface LeagueWalletTemplateProps extends TemplateProps<LeagueWalletViewData> {
|
||||||
onWithdraw?: (amount: number) => void;
|
onWithdraw?: (amount: number) => void;
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import { NotFoundScreen } from '@/components/errors/NotFoundScreen';
|
import { NotFoundScreen } from '@/components/errors/NotFoundScreen';
|
||||||
|
import { ViewData } from '@/lib/contracts/view-data/ViewData';
|
||||||
|
|
||||||
export interface NotFoundViewData {
|
export interface NotFoundViewData extends ViewData {
|
||||||
errorCode: string;
|
errorCode: string;
|
||||||
title: string;
|
title: string;
|
||||||
message: string;
|
message: string;
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ import { Box } from '@/ui/Box';
|
|||||||
import { Container } from '@/ui/Container';
|
import { Container } from '@/ui/Container';
|
||||||
import { Grid } from '@/ui/Grid';
|
import { Grid } from '@/ui/Grid';
|
||||||
import { GridItem } from '@/ui/GridItem';
|
import { GridItem } from '@/ui/GridItem';
|
||||||
import { Stack } from '@/ui/Stack';
|
|
||||||
import { Skeleton } from '@/ui/Skeleton';
|
import { Skeleton } from '@/ui/Skeleton';
|
||||||
|
import { Stack } from '@/ui/Stack';
|
||||||
import { Text } from '@/ui/Text';
|
import { Text } from '@/ui/Text';
|
||||||
|
|
||||||
export interface RaceDetailEntryViewModel {
|
export interface RaceDetailEntryViewModel {
|
||||||
@@ -58,7 +58,7 @@ export interface RaceDetailRegistration {
|
|||||||
canRegister: boolean;
|
canRegister: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RaceDetailViewData {
|
export interface RaceDetailViewData extends ViewData {
|
||||||
race: RaceDetailRace;
|
race: RaceDetailRace;
|
||||||
league?: RaceDetailLeague;
|
league?: RaceDetailLeague;
|
||||||
entryList: RaceDetailEntryViewModel[];
|
entryList: RaceDetailEntryViewModel[];
|
||||||
|
|||||||
@@ -2,12 +2,12 @@
|
|||||||
|
|
||||||
import { RaceDetailsHeader } from '@/components/races/RaceDetailsHeader';
|
import { RaceDetailsHeader } from '@/components/races/RaceDetailsHeader';
|
||||||
import { RaceResultsTable } from '@/components/races/RaceResultsTable';
|
import { RaceResultsTable } from '@/components/races/RaceResultsTable';
|
||||||
import type { RaceResultsViewData } from '@/lib/view-data/races/RaceResultsViewData';
|
import type { RaceResultsViewData } from '@/lib/view-data/RaceResultsViewData';
|
||||||
import { Box } from '@/ui/Box';
|
import { Box } from '@/ui/Box';
|
||||||
import { Container } from '@/ui/Container';
|
import { Container } from '@/ui/Container';
|
||||||
import { Icon } from '@/ui/Icon';
|
|
||||||
import { Grid } from '@/ui/Grid';
|
import { Grid } from '@/ui/Grid';
|
||||||
import { GridItem } from '@/ui/GridItem';
|
import { GridItem } from '@/ui/GridItem';
|
||||||
|
import { Icon } from '@/ui/Icon';
|
||||||
import { Stack } from '@/ui/Stack';
|
import { Stack } from '@/ui/Stack';
|
||||||
import { Text } from '@/ui/Text';
|
import { Text } from '@/ui/Text';
|
||||||
import { AlertTriangle, Trophy, Zap, type LucideIcon } from 'lucide-react';
|
import { AlertTriangle, Trophy, Zap, type LucideIcon } from 'lucide-react';
|
||||||
|
|||||||
@@ -5,12 +5,12 @@ import { StewardingTabs } from '@/components/leagues/StewardingTabs';
|
|||||||
import { RaceDetailsHeader } from '@/components/races/RaceDetailsHeader';
|
import { RaceDetailsHeader } from '@/components/races/RaceDetailsHeader';
|
||||||
import { RacePenaltyRow } from '@/components/races/RacePenaltyRowWrapper';
|
import { RacePenaltyRow } from '@/components/races/RacePenaltyRowWrapper';
|
||||||
import { RaceStewardingStats } from '@/components/races/RaceStewardingStats';
|
import { RaceStewardingStats } from '@/components/races/RaceStewardingStats';
|
||||||
import type { RaceStewardingViewData } from '@/lib/view-data/races/RaceStewardingViewData';
|
import type { RaceStewardingViewData } from '@/lib/view-data/RaceStewardingViewData';
|
||||||
import { Box } from '@/ui/Box';
|
import { Box } from '@/ui/Box';
|
||||||
import { Container } from '@/ui/Container';
|
import { Container } from '@/ui/Container';
|
||||||
import { Icon } from '@/ui/Icon';
|
|
||||||
import { Grid } from '@/ui/Grid';
|
import { Grid } from '@/ui/Grid';
|
||||||
import { GridItem } from '@/ui/GridItem';
|
import { GridItem } from '@/ui/GridItem';
|
||||||
|
import { Icon } from '@/ui/Icon';
|
||||||
import { Stack } from '@/ui/Stack';
|
import { Stack } from '@/ui/Stack';
|
||||||
import { Text } from '@/ui/Text';
|
import { Text } from '@/ui/Text';
|
||||||
import { CheckCircle, Flag, Gavel, Info } from 'lucide-react';
|
import { CheckCircle, Flag, Gavel, Info } from 'lucide-react';
|
||||||
|
|||||||
@@ -2,11 +2,11 @@
|
|||||||
|
|
||||||
import { RulebookTabs, type RulebookSection } from '@/components/leagues/RulebookTabs';
|
import { RulebookTabs, type RulebookSection } from '@/components/leagues/RulebookTabs';
|
||||||
import { PointsTable } from '@/components/races/PointsTable';
|
import { PointsTable } from '@/components/races/PointsTable';
|
||||||
import type { RulebookViewData } from '@/lib/view-data/leagues/RulebookViewData';
|
import type { RulebookViewData } from '@/lib/view-data/RulebookViewData';
|
||||||
import { Box } from '@/ui/Box';
|
import { Box } from '@/ui/Box';
|
||||||
|
import { Grid } from '@/ui/Grid';
|
||||||
import { Heading } from '@/ui/Heading';
|
import { Heading } from '@/ui/Heading';
|
||||||
import { Icon } from '@/ui/Icon';
|
import { Icon } from '@/ui/Icon';
|
||||||
import { Grid } from '@/ui/Grid';
|
|
||||||
import { Stack } from '@/ui/Stack';
|
import { Stack } from '@/ui/Stack';
|
||||||
import { Surface } from '@/ui/Surface';
|
import { Surface } from '@/ui/Surface';
|
||||||
import { Table, TableBody, TableCell, TableHead, TableHeaderCell, TableRow } from '@/ui/Table';
|
import { Table, TableBody, TableCell, TableHead, TableHeaderCell, TableRow } from '@/ui/Table';
|
||||||
|
|||||||
@@ -3,12 +3,13 @@
|
|||||||
import { ErrorDetails } from '@/components/errors/ErrorDetails';
|
import { ErrorDetails } from '@/components/errors/ErrorDetails';
|
||||||
import { RecoveryActions } from '@/components/errors/RecoveryActions';
|
import { RecoveryActions } from '@/components/errors/RecoveryActions';
|
||||||
import { ServerErrorPanel } from '@/components/errors/ServerErrorPanel';
|
import { ServerErrorPanel } from '@/components/errors/ServerErrorPanel';
|
||||||
|
import { ViewData } from '@/lib/contracts/view-data/ViewData';
|
||||||
import { Box } from '@/ui/Box';
|
import { Box } from '@/ui/Box';
|
||||||
import { Glow } from '@/ui/Glow';
|
import { Glow } from '@/ui/Glow';
|
||||||
import { Stack } from '@/ui/Stack';
|
import { Stack } from '@/ui/Stack';
|
||||||
import { Surface } from '@/ui/Surface';
|
import { Surface } from '@/ui/Surface';
|
||||||
|
|
||||||
export interface ServerErrorViewData {
|
export interface ServerErrorViewData extends ViewData {
|
||||||
error: Error & { digest?: string };
|
error: Error & { digest?: string };
|
||||||
incidentId?: string;
|
incidentId?: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,16 +15,16 @@ import { InfoBanner } from '@/ui/InfoBanner';
|
|||||||
import { Stack } from '@/ui/Stack';
|
import { Stack } from '@/ui/Stack';
|
||||||
import { Text } from '@/ui/Text';
|
import { Text } from '@/ui/Text';
|
||||||
import {
|
import {
|
||||||
Building2,
|
Building2,
|
||||||
CreditCard,
|
CreditCard,
|
||||||
Download,
|
Download,
|
||||||
ExternalLink,
|
ExternalLink,
|
||||||
LucideIcon,
|
LucideIcon,
|
||||||
Percent,
|
Percent,
|
||||||
Receipt
|
Receipt
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
|
|
||||||
export interface SponsorBillingViewData {
|
export interface SponsorBillingViewData extends ViewData {
|
||||||
stats: {
|
stats: {
|
||||||
totalSpent: number;
|
totalSpent: number;
|
||||||
pendingAmount: number;
|
pendingAmount: number;
|
||||||
|
|||||||
@@ -7,19 +7,19 @@ import { Container } from '@/ui/Container';
|
|||||||
import { Icon } from '@/ui/Icon';
|
import { Icon } from '@/ui/Icon';
|
||||||
import { Stack } from '@/ui/Stack';
|
import { Stack } from '@/ui/Stack';
|
||||||
import {
|
import {
|
||||||
BarChart3,
|
BarChart3,
|
||||||
Check,
|
Check,
|
||||||
Clock,
|
Clock,
|
||||||
Eye,
|
Eye,
|
||||||
LucideIcon,
|
LucideIcon,
|
||||||
Search
|
Search
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
export type SponsorshipType = 'all' | 'leagues' | 'teams' | 'drivers' | 'races' | 'platform';
|
export type SponsorshipType = 'all' | 'leagues' | 'teams' | 'drivers' | 'races' | 'platform';
|
||||||
export type SponsorshipStatus = 'all' | 'active' | 'pending_approval' | 'approved' | 'rejected' | 'expired';
|
export type SponsorshipStatus = 'all' | 'active' | 'pending_approval' | 'approved' | 'rejected' | 'expired';
|
||||||
|
|
||||||
export interface SponsorCampaignsViewData {
|
export interface SponsorCampaignsViewData extends ViewData {
|
||||||
sponsorships: Array<{
|
sponsorships: Array<{
|
||||||
id: string;
|
id: string;
|
||||||
type: string;
|
type: string;
|
||||||
|
|||||||
@@ -5,36 +5,36 @@ import { PricingTableShell, PricingTier } from '@/components/sponsors/PricingTab
|
|||||||
import { SponsorBrandingPreview } from '@/components/sponsors/SponsorBrandingPreview';
|
import { SponsorBrandingPreview } from '@/components/sponsors/SponsorBrandingPreview';
|
||||||
import { SponsorDashboardHeader } from '@/components/sponsors/SponsorDashboardHeader';
|
import { SponsorDashboardHeader } from '@/components/sponsors/SponsorDashboardHeader';
|
||||||
import { SponsorStatusChip } from '@/components/sponsors/SponsorStatusChip';
|
import { SponsorStatusChip } from '@/components/sponsors/SponsorStatusChip';
|
||||||
|
import { TemplateProps } from '@/lib/contracts/components/ComponentContracts';
|
||||||
|
import { ViewData } from '@/lib/contracts/view-data/ViewData';
|
||||||
import { routes } from '@/lib/routing/RouteConfig';
|
import { routes } from '@/lib/routing/RouteConfig';
|
||||||
import { siteConfig } from '@/lib/siteConfig';
|
import { siteConfig } from '@/lib/siteConfig';
|
||||||
import { Box } from '@/ui/Box';
|
import { Box } from '@/ui/Box';
|
||||||
import { Button } from '@/ui/Button';
|
import { Button } from '@/ui/Button';
|
||||||
import { Stack } from '@/ui/Stack';
|
|
||||||
import { Text } from '@/ui/Text';
|
|
||||||
import { Icon } from '@/ui/Icon';
|
|
||||||
import { Card } from '@/ui/Card';
|
import { Card } from '@/ui/Card';
|
||||||
import { Container } from '@/ui/Container';
|
import { Container } from '@/ui/Container';
|
||||||
import { Heading } from '@/ui/Heading';
|
|
||||||
import { Link } from '@/ui/Link';
|
|
||||||
import { Grid } from '@/ui/Grid';
|
import { Grid } from '@/ui/Grid';
|
||||||
import { GridItem } from '@/ui/GridItem';
|
import { GridItem } from '@/ui/GridItem';
|
||||||
|
import { Heading } from '@/ui/Heading';
|
||||||
|
import { Icon } from '@/ui/Icon';
|
||||||
|
import { Link } from '@/ui/Link';
|
||||||
|
import { Stack } from '@/ui/Stack';
|
||||||
import { Surface } from '@/ui/Surface';
|
import { Surface } from '@/ui/Surface';
|
||||||
|
import { Text } from '@/ui/Text';
|
||||||
import {
|
import {
|
||||||
BarChart3,
|
BarChart3,
|
||||||
Calendar,
|
Calendar,
|
||||||
CreditCard,
|
CreditCard,
|
||||||
Eye,
|
Eye,
|
||||||
FileText,
|
FileText,
|
||||||
Flag,
|
Flag,
|
||||||
Megaphone,
|
Megaphone,
|
||||||
TrendingUp,
|
TrendingUp,
|
||||||
Trophy,
|
Trophy,
|
||||||
type LucideIcon
|
type LucideIcon
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
import { TemplateProps } from '@/lib/contracts/components/ComponentContracts';
|
|
||||||
import { ViewData } from '@/lib/contracts/view-data/ViewData';
|
|
||||||
|
|
||||||
export interface SponsorLeagueDetailViewData extends ViewData {
|
export interface SponsorLeagueDetailViewData extends ViewData extends ViewData {
|
||||||
league: {
|
league: {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
|
|||||||
@@ -8,21 +8,21 @@ import { Box } from '@/ui/Box';
|
|||||||
import { Button } from '@/ui/Button';
|
import { Button } from '@/ui/Button';
|
||||||
import { Card } from '@/ui/Card';
|
import { Card } from '@/ui/Card';
|
||||||
import { Container } from '@/ui/Container';
|
import { Container } from '@/ui/Container';
|
||||||
|
import { Grid } from '@/ui/Grid';
|
||||||
|
import { GridItem } from '@/ui/GridItem';
|
||||||
import { Heading } from '@/ui/Heading';
|
import { Heading } from '@/ui/Heading';
|
||||||
import { Icon } from '@/ui/Icon';
|
import { Icon } from '@/ui/Icon';
|
||||||
import { Input } from '@/ui/Input';
|
import { Input } from '@/ui/Input';
|
||||||
import { Link } from '@/ui/Link';
|
import { Link } from '@/ui/Link';
|
||||||
import { Grid } from '@/ui/Grid';
|
|
||||||
import { GridItem } from '@/ui/GridItem';
|
|
||||||
import { Stack } from '@/ui/Stack';
|
import { Stack } from '@/ui/Stack';
|
||||||
import { Surface } from '@/ui/Surface';
|
import { Surface } from '@/ui/Surface';
|
||||||
import { Text } from '@/ui/Text';
|
import { Text } from '@/ui/Text';
|
||||||
import {
|
import {
|
||||||
Car,
|
Car,
|
||||||
Megaphone,
|
Megaphone,
|
||||||
Search,
|
Search,
|
||||||
Trophy,
|
Trophy,
|
||||||
Users,
|
Users,
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
|
|
||||||
interface AvailableLeague {
|
interface AvailableLeague {
|
||||||
@@ -47,7 +47,7 @@ export type SortOption = 'rating' | 'drivers' | 'price' | 'views';
|
|||||||
export type TierFilter = 'all' | 'premium' | 'standard' | 'starter';
|
export type TierFilter = 'all' | 'premium' | 'standard' | 'starter';
|
||||||
export type AvailabilityFilter = 'all' | 'main' | 'secondary';
|
export type AvailabilityFilter = 'all' | 'main' | 'secondary';
|
||||||
|
|
||||||
export interface SponsorLeaguesViewData {
|
export interface SponsorLeaguesViewData extends ViewData {
|
||||||
leagues: AvailableLeague[];
|
leagues: AvailableLeague[];
|
||||||
stats: {
|
stats: {
|
||||||
total: number;
|
total: number;
|
||||||
|
|||||||
@@ -11,15 +11,15 @@ import { Stack } from '@/ui/Stack';
|
|||||||
import { Text } from '@/ui/Text';
|
import { Text } from '@/ui/Text';
|
||||||
import { Toggle } from '@/ui/Toggle';
|
import { Toggle } from '@/ui/Toggle';
|
||||||
import {
|
import {
|
||||||
AlertCircle,
|
AlertCircle,
|
||||||
Bell,
|
Bell,
|
||||||
Building2,
|
Building2,
|
||||||
RefreshCw,
|
RefreshCw,
|
||||||
Save
|
Save
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
export interface SponsorSettingsViewData {
|
export interface SponsorSettingsViewData extends ViewData {
|
||||||
profile: {
|
profile: {
|
||||||
companyName: string;
|
companyName: string;
|
||||||
contactName: string;
|
contactName: string;
|
||||||
|
|||||||
@@ -6,13 +6,13 @@ import { ReviewProtestModal } from '@/components/leagues/ReviewProtestModal';
|
|||||||
import { StewardingQueuePanel } from '@/components/leagues/StewardingQueuePanel';
|
import { StewardingQueuePanel } from '@/components/leagues/StewardingQueuePanel';
|
||||||
import { StewardingStats } from '@/components/leagues/StewardingStats';
|
import { StewardingStats } from '@/components/leagues/StewardingStats';
|
||||||
import { PenaltyFAB } from '@/components/races/PenaltyFAB';
|
import { PenaltyFAB } from '@/components/races/PenaltyFAB';
|
||||||
import type { StewardingViewData } from '@/lib/view-data/leagues/StewardingViewData';
|
import { TemplateProps } from '@/lib/contracts/components/ComponentContracts';
|
||||||
|
import type { StewardingViewData } from '@/lib/view-data/StewardingViewData';
|
||||||
import { Box } from '@/ui/Box';
|
import { Box } from '@/ui/Box';
|
||||||
import { Button } from '@/ui/Button';
|
import { Button } from '@/ui/Button';
|
||||||
|
import { Card } from '@/ui/Card';
|
||||||
import { Stack } from '@/ui/Stack';
|
import { Stack } from '@/ui/Stack';
|
||||||
import { Text } from '@/ui/Text';
|
import { Text } from '@/ui/Text';
|
||||||
import { Card } from '@/ui/Card';
|
|
||||||
import { TemplateProps } from '@/lib/contracts/components/ComponentContracts';
|
|
||||||
|
|
||||||
interface StewardingTemplateProps extends TemplateProps<StewardingViewData> {
|
interface StewardingTemplateProps extends TemplateProps<StewardingViewData> {
|
||||||
activeTab: 'pending' | 'history';
|
activeTab: 'pending' | 'history';
|
||||||
|
|||||||
@@ -3,8 +3,8 @@
|
|||||||
import { AuthCard } from '@/components/auth/AuthCard';
|
import { AuthCard } from '@/components/auth/AuthCard';
|
||||||
import { AuthFooterLinks } from '@/components/auth/AuthFooterLinks';
|
import { AuthFooterLinks } from '@/components/auth/AuthFooterLinks';
|
||||||
import { AuthForm } from '@/components/auth/AuthForm';
|
import { AuthForm } from '@/components/auth/AuthForm';
|
||||||
import { ForgotPasswordViewData } from '@/lib/builders/view-data/types/ForgotPasswordViewData';
|
|
||||||
import { routes } from '@/lib/routing/RouteConfig';
|
import { routes } from '@/lib/routing/RouteConfig';
|
||||||
|
import { ForgotPasswordViewData } from '@/lib/view-data/ForgotPasswordViewData';
|
||||||
import { Button } from '@/ui/Button';
|
import { Button } from '@/ui/Button';
|
||||||
import { Group } from '@/ui/Group';
|
import { Group } from '@/ui/Group';
|
||||||
import { Icon } from '@/ui/Icon';
|
import { Icon } from '@/ui/Icon';
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user