/** * Luqta SDK UI Renderer * * Handles the complete pre-configured UI flow: * - Contest list display * - Participation flow * - Contest detail with levels * - Level completion by type * - Congratulation popups */ import { BrandingConfig, Contest, LuqtaError, UIAction } from '../types'; interface RendererConfig { containerId: string; branding?: BrandingConfig; locale?: 'en' | 'ar'; rtl?: boolean; showProfileIcon?: boolean; onAction?: (action: UIAction) => void; onError?: (error: LuqtaError) => void; } type ApiClient = { getPublicContests: () => Promise; fetchContests: (params?: { page?: number; per_page?: number; }) => Promise; isSdkReady: () => boolean; getContestDetailsProgress: (contestId: number) => Promise; getContestDetails: (contestId: number, accessCode?: string) => Promise; participateContest: (contestId: number, accessCode?: string) => Promise; contests: { participate: (contestId: number, accessCode?: string) => Promise; getProgress: (contestId: number) => Promise; compete: (contestId: number) => Promise; }; levels: { complete: (levelId: number, data: any) => Promise; completeWithImage: (levelId: number, imageBase64: string) => Promise; getCongratulation: (levelId: number, contestId: number) => Promise; }; quiz: { start: (quizId: number, levelId: number) => Promise; submitAnswer: (attemptId: number, questionId: number, optionId: number, levelId: number) => Promise; submit: (attemptId: number) => Promise; }; isInitialized: () => boolean; initializeUser: () => Promise; applicationRequest: (endpoint: string, options?: any) => Promise; profile: { get: () => Promise; }; }; export declare class LuqtaUIRenderer { private container; private config; private client; private state; private t; private static readonly ACCESS_CODE_CACHE_KEY; constructor(client: ApiClient, config: RendererConfig); private getAccessCodeFromCache; private setAccessCodeToCache; private removeAccessCodeFromCache; /** * Initialize and render the UI */ render(): Promise; /** * Render the UI with pre-loaded contests * Used when contests are already fetched during SDK initialization */ renderWithContests(contests: Contest[]): Promise; /** * Refresh the contest list */ refresh(): Promise; private loadContests; private showLoading; private renderError; private renderContestList; private initProfileIconDrag; private openProfileSheet; private renderProfileSheet; /** * Initialize carousel auto-rotation and dot click handlers */ private initializeCarousels; private renderEmptyState; private renderContestCard; private renderContestDetail; /** * Renders a level card for the detail page (Figma design) */ private renderDetailLevelCard; /** * Renders a company card for the detail page */ private renderCompanyCard; /** * Renders a prize card for the detail page */ private renderPrizeCard; /** * Initialize carousel for detail page banner */ private initializeDetailCarousel; private renderLevelsList; private renderLevelCard; private showParticipateModal; /** * Shows contest info page with details fetched from API */ private showContestInfoModal; /** * Extract level progress from API response * The API returns level_progress array inside each level */ private extractLevelProgressFromResponse; /** * Check if user is participating based on API response */ private checkUserParticipation; /** * Shows access code input modal for private contests */ private showAccessCodeModal; /** * Renders the contest info as a full page with banners and company info * @param data - Contest details from API * @param isParticipating - Whether user is already participating (optional) * @param levelProgress - Level progress data if participating (optional) */ private renderContestInfoPage; /** * Handle participation from info page */ private handleInfoPageParticipation; /** * Initialize carousel for info page banner */ private initializeInfoPageCarousel; private showLevelModal; private showCongratulationModal; /** * Shows contest completion modal with full contest data from compete API */ private showContestCompletionModal; private closeModal; private onContestClick; /** * Shows a loading overlay while fetching data */ private showLoadingOverlay; /** * Hides the loading overlay */ private hideLoadingOverlay; /** * Shows participation required modal when user hasn't joined the contest */ private showParticipationRequiredModal; /** * Sets up handlers for the participation required modal */ private setupParticipationModalHandlers; private setupModalHandlers; private activeCameraStream; private setupLevelModalHandlers; /** * Starts the QR code scanner using device camera */ private startQRScanner; /** * Scans QR code from video stream * Uses canvas to capture frames and check for QR patterns */ private scanQRFromVideo; /** * Handles detected QR code data */ private handleQRDetected; /** * Stops the camera stream */ private stopCameraStream; private onLevelCompleted; private refreshContestDetail; private currentQuizState; private showQuizModal; private renderQuizQuestion; private setupQuizHandlers; private handleQuizCompletion; private showQuizResultModal; private formatTime; private calculateContestProgress; private calculateDaysLeft; private calculateTimeLeft; private isLevelCompleted; private fileToBase64; /** * Parse a level date value. Accepts ISO strings and numeric epoch timestamps * (seconds or milliseconds — `level_timeline` often arrives as a millisecond * timestamp). Returns null if the value cannot be parsed. */ private parseLevelDate; /** * Show a modal popup used by both level-availability and * contest-availability guards. */ private showUnavailableDialog; private showToast; } export {};