From 98a22b4d20e20d6187dabd1b4f6a6b4c8fb5730a Mon Sep 17 00:00:00 2001 From: AbuJulaybeeb Date: Wed, 25 Mar 2026 11:44:41 +0100 Subject: [PATCH 01/10] feat: implement advanced PWA features (#85) --- src/app/layout.tsx | 3 + src/components/pwa/AppUpdateManager.tsx | 48 ++++++++ src/components/pwa/NativeIntegrationLayer.tsx | 55 +++++++++ src/components/pwa/OfflineSyncManager.tsx | 50 ++++++++ src/components/pwa/PWAManager.tsx | 31 +++++ src/hooks/usePWA.tsx | 107 ++++++++++++++++++ src/public/manifest.json | 21 ++++ src/serviceWorker.ts | 104 +++++++++++++++++ 8 files changed, 419 insertions(+) create mode 100644 src/components/pwa/AppUpdateManager.tsx create mode 100644 src/components/pwa/NativeIntegrationLayer.tsx create mode 100644 src/components/pwa/OfflineSyncManager.tsx create mode 100644 src/components/pwa/PWAManager.tsx create mode 100644 src/hooks/usePWA.tsx create mode 100644 src/public/manifest.json create mode 100644 src/serviceWorker.ts diff --git a/src/app/layout.tsx b/src/app/layout.tsx index d47f2caf..ec721867 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -9,6 +9,7 @@ import { CulturalAdaptationManager } from '@/components/i18n/CulturalAdaptationM import PerformanceMonitor from '@/components/performance/PerformanceMonitor'; import PrefetchingEngine from '@/components/performance/PrefetchingEngine'; import StateManagerIntegration from '@/components/state/StateManagerIntegration'; +import { PWAManager } from '@/components/pwa/PWAManager'; const geistSans = Geist({ // ... @@ -24,6 +25,7 @@ const geistMono = Geist_Mono({ export const metadata: Metadata = { title: 'TeachLink - Offline Learning Platform', description: 'Learn anywhere, anytime with offline capabilities', + manifest: '/manifest.json', }; export default function RootLayout({ @@ -41,6 +43,7 @@ export default function RootLayout({ + diff --git a/src/components/pwa/AppUpdateManager.tsx b/src/components/pwa/AppUpdateManager.tsx new file mode 100644 index 00000000..2f8e9d11 --- /dev/null +++ b/src/components/pwa/AppUpdateManager.tsx @@ -0,0 +1,48 @@ +'use client'; + +import React from 'react'; +import { usePWA } from '@/hooks/usePWA'; +import { RefreshCw, X } from 'lucide-react'; + +export const AppUpdateManager: React.FC = () => { + const { updateAvailable, updateApp } = usePWA(); + const [show, setShow] = React.useState(true); + + if (!updateAvailable || !show) return null; + + return ( +
+
+
+ +
+
+

Update Available

+

+ A new version of TeachLink is available with new features and improvements. +

+
+ + +
+
+ +
+
+ ); +}; diff --git a/src/components/pwa/NativeIntegrationLayer.tsx b/src/components/pwa/NativeIntegrationLayer.tsx new file mode 100644 index 00000000..c857e227 --- /dev/null +++ b/src/components/pwa/NativeIntegrationLayer.tsx @@ -0,0 +1,55 @@ +'use client'; + +import React from 'react'; +import { Bell, Camera } from 'lucide-react'; + +export const NativeIntegrationLayer: React.FC = () => { + const requestNotificationPermission = async () => { + if ('Notification' in window) { + const permission = await Notification.requestPermission(); + if (permission === 'granted') { + new Notification('TeachLink', { + body: 'You will now receive updates and reminders!', + icon: '/icons/icon-192x192.png', + }); + } + } + }; + + const testCamera = async () => { + try { + const stream = await navigator.mediaDevices.getUserMedia({ video: true }); + // In a real app, this would open a camera modal or start a scan + console.log('Camera access granted'); + // Stop stream immediately for demo + stream.getTracks().forEach(track => track.stop()); + } catch (err) { + console.error('Camera access denied:', err); + } + }; + + return ( +
+ {/* + This component can provide utility functions to other components + via a context or simply by being present to handle global native events. + For now, it's a placeholder for native feature logic. + */} +
+ ); +}; + +// Hook for using native features +export const useNativeFeatures = () => { + const showNotification = (title: string, options?: NotificationOptions) => { + if ('Notification' in window && Notification.permission === 'granted') { + new Notification(title, options); + } + }; + + const openCamera = async () => { + return await navigator.mediaDevices.getUserMedia({ video: true }); + }; + + return { showNotification, openCamera }; +}; diff --git a/src/components/pwa/OfflineSyncManager.tsx b/src/components/pwa/OfflineSyncManager.tsx new file mode 100644 index 00000000..fda5fa00 --- /dev/null +++ b/src/components/pwa/OfflineSyncManager.tsx @@ -0,0 +1,50 @@ +'use client'; + +import React, { useState, useEffect } from 'react'; +import { RefreshCw, CheckCircle2, AlertCircle } from 'lucide-react'; + +export const OfflineSyncManager: React.FC = () => { + const [syncStatus, setSyncStatus] = useState<'idle' | 'syncing' | 'synced' | 'error'>('idle'); + const [show, setShow] = useState(false); + + useEffect(() => { + // Listen for custom sync events from service worker if needed + // In a real app, we'd use the SyncManager API or a shared state (Zustand/Context) + // For now, we'll listen for a custom event + const handleSyncEvent = (e: any) => { + setSyncStatus(e.detail.status); + setShow(true); + if (e.detail.status === 'synced') { + setTimeout(() => setShow(false), 3000); + } + }; + + window.addEventListener('pwa-sync-status', handleSyncEvent); + return () => window.removeEventListener('pwa-sync-status', handleSyncEvent); + }, []); + + if (!show) return null; + + return ( +
+ {syncStatus === 'syncing' && ( + <> + + Synchronizing data... + + )} + {syncStatus === 'synced' && ( + <> + + Data synchronized + + )} + {syncStatus === 'error' && ( + <> + + Sync failed + + )} +
+ ); +}; diff --git a/src/components/pwa/PWAManager.tsx b/src/components/pwa/PWAManager.tsx new file mode 100644 index 00000000..bf19de41 --- /dev/null +++ b/src/components/pwa/PWAManager.tsx @@ -0,0 +1,31 @@ +'use client'; + +import React, { useEffect } from 'react'; +import { usePWA } from '@/hooks/usePWA'; +import { AppUpdateManager } from './AppUpdateManager'; +import { OfflineSyncManager } from './OfflineSyncManager'; +import { NativeIntegrationLayer } from './NativeIntegrationLayer'; + +export const PWAManager: React.FC = () => { + const { registerServiceWorker, isOffline } = usePWA(); + + useEffect(() => { + registerServiceWorker(); + }, [registerServiceWorker]); + + return ( + <> + + + + + {/* Offline Status Toast */} + {isOffline && ( +
+ + Offline Mode +
+ )} + + ); +}; diff --git a/src/hooks/usePWA.tsx b/src/hooks/usePWA.tsx new file mode 100644 index 00000000..a9223ce6 --- /dev/null +++ b/src/hooks/usePWA.tsx @@ -0,0 +1,107 @@ +'use client'; + +import { useState, useEffect, useCallback } from 'react'; + +interface BeforeInstallPromptEvent extends Event { + readonly platforms: string[]; + readonly userChoice: Promise<{ + outcome: 'accepted' | 'dismissed'; + platform: string; + }>; + prompt(): Promise; +} + +export const usePWA = () => { + const [installPrompt, setInstallPrompt] = useState(null); + const [isInstalled, setIsInstalled] = useState(false); + const [updateAvailable, setUpdateAvailable] = useState(false); + const [registration, setRegistration] = useState(null); + const [isOffline, setIsOffline] = useState(false); + + useEffect(() => { + // Check if app is already installed + if (window.matchMedia('(display-mode: standalone)').matches) { + setIsInstalled(true); + } + + // Monitor online/offline status + const handleOnline = () => setIsOffline(false); + const handleOffline = () => setIsOffline(true); + + window.addEventListener('online', handleOnline); + window.addEventListener('offline', handleOffline); + setIsOffline(!navigator.onLine); + + // Capture install prompt + const handleBeforeInstallPrompt = (e: Event) => { + e.preventDefault(); + setInstallPrompt(e as BeforeInstallPromptEvent); + }; + + window.addEventListener('beforeinstallprompt', handleBeforeInstallPrompt); + + // Track installation + window.addEventListener('appinstalled', () => { + setIsInstalled(true); + setInstallPrompt(null); + }); + + return () => { + window.removeEventListener('online', handleOnline); + window.removeEventListener('offline', handleOffline); + window.removeEventListener('beforeinstallprompt', handleBeforeInstallPrompt); + }; + }, []); + + const registerServiceWorker = useCallback(async () => { + if ('serviceWorker' in navigator && process.env.NODE_ENV === 'production') { + try { + const reg = await navigator.serviceWorker.register('/serviceWorker.js'); + setRegistration(reg); + + reg.addEventListener('updatefound', () => { + const newWorker = reg.installing; + if (newWorker) { + newWorker.addEventListener('statechange', () => { + if (newWorker.state === 'installed' && navigator.serviceWorker.controller) { + setUpdateAvailable(true); + } + }); + } + }); + } catch (error) { + console.error('Service worker registration failed:', error); + } + } + }, []); + + const installApp = async () => { + if (!installPrompt) return; + await installPrompt.prompt(); + const { outcome } = await installPrompt.userChoice; + if (outcome === 'accepted') { + setInstallPrompt(null); + } + }; + + const updateApp = () => { + if (registration?.waiting) { + registration.waiting.postMessage({ type: 'SKIP_WAITING' }); + registration.waiting.addEventListener('statechange', (e) => { + if ((e.target as ServiceWorker).state === 'activated') { + window.location.reload(); + } + }); + } + }; + + return { + canInstall: !!installPrompt, + isInstalled, + updateAvailable, + isOffline, + installApp, + updateApp, + registerServiceWorker, + }; +}; diff --git a/src/public/manifest.json b/src/public/manifest.json new file mode 100644 index 00000000..59fdfc84 --- /dev/null +++ b/src/public/manifest.json @@ -0,0 +1,21 @@ +{ + "name": "TeachLink", + "short_name": "TeachLink", + "description": "Learn anytime, anywhere with offline capabilities", + "start_url": "/", + "display": "standalone", + "background_color": "#ffffff", + "theme_color": "#2563eb", + "icons": [ + { + "src": "/icons/icon-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/icons/icon-512x512.png", + "sizes": "512x512", + "type": "image/png" + } + ] +} diff --git a/src/serviceWorker.ts b/src/serviceWorker.ts new file mode 100644 index 00000000..ac0a493b --- /dev/null +++ b/src/serviceWorker.ts @@ -0,0 +1,104 @@ +/// +import { clientsClaim } from 'workbox-core'; +import { ExpirationPlugin } from 'workbox-expiration'; +import { precacheAndRoute, createHandlerBoundToURL } from 'workbox-precaching'; +import { registerRoute, NavigationRoute } from 'workbox-routing'; +import { StaleWhileRevalidate, NetworkFirst, CacheFirst } from 'workbox-strategies'; +import { BackgroundSyncPlugin } from 'workbox-background-sync'; + +declare const self: ServiceWorkerGlobalScope; + +clientsClaim(); + +// Precache all of the assets generated by your build process. +// Their URLs are injected into the manifest variable below. +// This variable must be present somewhere in your service worker file, +// even if you decide not to use precaching. See https://cra.link/PWA +precacheAndRoute(self.__WB_MANIFEST || []); + +// Set up App Shell-style routing, so that navigation requests are fulfilled with your index.html shell. +// This is for Single Page Apps. +const fileExtensionRegexp = new RegExp('/[^/?]+\\.[^/]+$'); +registerRoute( + // Return false to exempt requests from being fulfilled by index.html. + ({ request, url }: { request: Request; url: URL }) => { + // If this isn't a navigation, skip. + if (request.mode !== 'navigate') { + return false; + } + + // If this is a URL that starts with /_, skip. + if (url.pathname.startsWith('/_')) { + return false; + } + + // If this looks like a URL for a resource, because it has a file extension, skip. + if (url.pathname.match(fileExtensionRegexp)) { + return false; + } + + // Return true to signal that we want to use the handler. + return true; + }, + createHandlerBoundToURL('/index.html') +); + +// An example runtime caching route for requests that aren't handled by the precache, +// in this case same-origin .png requests like those from in public/ +registerRoute( + // Add in any other file extensions or routing criteria as needed. + ({ url }) => url.origin === self.location.origin && url.pathname.endsWith('.png'), + // Customize this strategy as needed, e.g., by changing to CacheFirst. + new StaleWhileRevalidate({ + cacheName: 'images', + plugins: [ + // Ensure that once this runtime cache reaches a maximum size the least-recently used images are removed. + new ExpirationPlugin({ maxEntries: 50 }), + ], + }) +); + +// Cache common external image providers +registerRoute( + ({ url }) => + url.hostname === 'images.unsplash.com' || + url.hostname === 'thumbs.dreamstime.com' || + url.hostname === 'static.vecteezy.com', + new StaleWhileRevalidate({ + cacheName: 'external-images', + plugins: [ + new ExpirationPlugin({ maxEntries: 100, maxAgeSeconds: 30 * 24 * 60 * 60 }), // 30 Days + ], + }) +); + +// Cache API requests +registerRoute( + ({ url }) => url.pathname.startsWith('/api/'), + new NetworkFirst({ + cacheName: 'api-responses', + plugins: [ + new ExpirationPlugin({ maxEntries: 50, maxAgeSeconds: 24 * 60 * 60 }), // 24 Hours + ], + }) +); + +// Background Sync for offline actions +const bgSyncPlugin = new BackgroundSyncPlugin('teachLinkSyncQueue', { + maxRetentionTime: 24 * 60, // Retry for max 24 Hours (in minutes) +}); + +registerRoute( + ({ url }) => url.pathname.startsWith('/api/sync/'), + new NetworkFirst({ + plugins: [bgSyncPlugin], + }), + 'POST' +); + +// This allows the web app to trigger skipWaiting via registration.waiting.postMessage({type: 'SKIP_WAITING'}) +self.addEventListener('message', (event) => { + if (event.data && event.data.type === 'SKIP_WAITING') { + self.skipWaiting(); + } +}); From f31c7be3d376d4627171698952d4d936ed11f2d9 Mon Sep 17 00:00:00 2001 From: AbuJulaybeeb Date: Wed, 25 Mar 2026 12:06:41 +0100 Subject: [PATCH 02/10] chore: synchronize package-lock.json with package.json --- package-lock.json | 708 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 690 insertions(+), 18 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7f053f89..1aecae0d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4774,6 +4774,27 @@ "dev": true, "license": "MIT" }, + "node_modules/@testing-library/dom": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz", + "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.3.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "picocolors": "1.1.1", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/@testing-library/jest-dom": { "version": "6.9.1", "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.9.1.tgz", @@ -5327,6 +5348,14 @@ "tslib": "^2.4.0" } }, + "node_modules/@types/aria-query": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", + "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/@types/chai": { "version": "5.2.3", "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", @@ -5408,6 +5437,28 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/eslint": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz", + "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, "node_modules/@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", @@ -5418,7 +5469,6 @@ "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true, "license": "MIT" }, "node_modules/@types/json5": { @@ -5454,7 +5504,6 @@ "version": "20.19.30", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.30.tgz", "integrity": "sha512-WJtwWJu7UdlvzEAUm484QNg5eAoq5QR08KDNx7g45Usrs2NtOPiX8ugDqmKdXkyL03rBqU5dYNYVQetEpBHq2g==", - "dev": true, "license": "MIT", "dependencies": { "undici-types": "~6.21.0" @@ -5464,14 +5513,12 @@ "version": "15.7.15", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", - "dev": true, "license": "MIT" }, "node_modules/@types/react": { "version": "18.3.27", "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.27.tgz", "integrity": "sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w==", - "dev": true, "license": "MIT", "dependencies": { "@types/prop-types": "*", @@ -5482,7 +5529,6 @@ "version": "18.3.7", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", - "dev": true, "license": "MIT", "peerDependencies": { "@types/react": "^18.0.0" @@ -6165,10 +6211,185 @@ "url": "https://opencollective.com/vitest" } }, + "node_modules/@webassemblyjs/ast": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", + "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@webassemblyjs/helper-numbers": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", + "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", + "license": "MIT", + "peer": true + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", + "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", + "license": "MIT", + "peer": true + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", + "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", + "license": "MIT", + "peer": true + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", + "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.13.2", + "@webassemblyjs/helper-api-error": "1.13.2", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", + "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", + "license": "MIT", + "peer": true + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", + "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/wasm-gen": "1.14.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", + "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", + "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", + "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", + "license": "MIT", + "peer": true + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", + "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/helper-wasm-section": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-opt": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1", + "@webassemblyjs/wast-printer": "1.14.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", + "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", + "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", + "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-api-error": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", + "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "license": "BSD-3-Clause", + "peer": true + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "license": "Apache-2.0", + "peer": true + }, "node_modules/acorn": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", - "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -6177,6 +6398,19 @@ "node": ">=0.4.0" } }, + "node_modules/acorn-import-phases": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz", + "integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10.13.0" + }, + "peerDependencies": { + "acorn": "^8.14.0" + } + }, "node_modules/acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", @@ -6214,6 +6448,48 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "license": "MIT", + "peer": true, + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "license": "MIT", + "peer": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT", + "peer": true + }, "node_modules/ansi-escapes": { "version": "7.3.0", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.3.0.tgz", @@ -6772,6 +7048,16 @@ "node": ">= 16" } }, + "node_modules/chrome-trace-event": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", + "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6.0" + } + }, "node_modules/class-variance-authority": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz", @@ -7306,6 +7592,14 @@ "node": ">=0.10.0" } }, + "node_modules/dom-accessibility-api": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/dom-helpers": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", @@ -7316,6 +7610,16 @@ "csstype": "^3.0.2" } }, + "node_modules/dompurify": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.7.tgz", + "integrity": "sha512-WhL/YuveyGXJaerVlMYGWhvQswa7myDG17P7Vu65EWC05o8vfeNbvNf4d/BOvH99+ZW+LlQsc1GDKMa1vNK6dw==", + "license": "(MPL-2.0 OR Apache-2.0)", + "peer": true, + "optionalDependencies": { + "@types/trusted-types": "^2.0.7" + } + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -7407,10 +7711,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.19.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.19.0.tgz", - "integrity": "sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==", - "dev": true, + "version": "5.20.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.20.1.tgz", + "integrity": "sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==", "license": "MIT", "dependencies": { "graceful-fs": "^4.2.4", @@ -8125,7 +8428,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" @@ -8138,7 +8440,6 @@ "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=4.0" @@ -8169,6 +8470,16 @@ "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", "license": "MIT" }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.8.x" + } + }, "node_modules/expect-type": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", @@ -8652,6 +8963,13 @@ "node": ">=10.13.0" } }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "license": "BSD-2-Clause", + "peer": true + }, "node_modules/glob/node_modules/minimatch": { "version": "10.1.1", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.1.1.tgz", @@ -8739,7 +9057,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -9451,6 +9768,37 @@ "node": ">=10" } }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "license": "MIT", + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, "node_modules/jiti": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", @@ -9539,6 +9887,13 @@ "dev": true, "license": "MIT" }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "license": "MIT", + "peer": true + }, "node_modules/json-schema": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", @@ -10076,6 +10431,20 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/loader-runner": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.1.tgz", + "integrity": "sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6.11.5" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -10261,6 +10630,17 @@ "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc" } }, + "node_modules/lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "dev": true, + "license": "MIT", + "peer": true, + "bin": { + "lz-string": "bin/bin.js" + } + }, "node_modules/magic-string": { "version": "0.30.21", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", @@ -10300,6 +10680,19 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, + "node_modules/marked": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-14.0.0.tgz", + "integrity": "sha512-uIj4+faQ+MgHgwUW1l2PsPglZLOLOT1uErt06dAPtx2kjteLAkbsd/0FiYg/MGS+i7ZKLb7w2WClxHkzOOuryQ==", + "license": "MIT", + "peer": true, + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 18" + } + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -10315,6 +10708,13 @@ "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", "license": "MIT" }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "license": "MIT", + "peer": true + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -10339,6 +10739,29 @@ "node": ">=8.6" } }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "peer": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/mimic-function": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", @@ -10394,6 +10817,17 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/monaco-editor": { + "version": "0.55.1", + "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.55.1.tgz", + "integrity": "sha512-jz4x+TJNFHwHtwuV9vA9rMujcZRb0CEilTEwG2rRSpe/A7Jdkuj8xPKttCgOh+v/lkHy7HsZ64oj+q3xoAFl9A==", + "license": "MIT", + "peer": true, + "dependencies": { + "dompurify": "3.2.7", + "marked": "14.0.0" + } + }, "node_modules/motion-dom": { "version": "12.29.2", "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.29.2.tgz", @@ -10456,6 +10890,13 @@ "dev": true, "license": "MIT" }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "license": "MIT", + "peer": true + }, "node_modules/next": { "version": "15.3.1", "resolved": "https://registry.npmjs.org/next/-/next-15.3.1.tgz", @@ -10985,6 +11426,36 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/prop-types": { "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", @@ -11363,6 +11834,14 @@ } } }, + "node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/react-redux": { "version": "9.2.0", "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz", @@ -11658,7 +12137,7 @@ "version": "4.57.1", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.57.1.tgz", "integrity": "sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "@types/estree": "1.0.8" @@ -11837,6 +12316,63 @@ "loose-envify": "^1.1.0" } }, + "node_modules/schema-utils": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.3.tgz", + "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/schema-utils/node_modules/ajv": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "license": "MIT", + "peer": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/schema-utils/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "license": "MIT", + "peer": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/schema-utils/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT", + "peer": true + }, "node_modules/semver": { "version": "7.7.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", @@ -12575,7 +13111,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -12630,6 +13165,40 @@ "node": ">=10" } }, + "node_modules/terser-webpack-plugin": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.4.0.tgz", + "integrity": "sha512-Bn5vxm48flOIfkdl5CaD2+1CiUVbonWQ3KQPyP7/EuIl9Gbzq/gQFOzaMFUEgVjB1396tcK0SG8XcNJ/2kDH8g==", + "license": "MIT", + "peer": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.25", + "jest-worker": "^27.4.5", + "schema-utils": "^4.3.0", + "terser": "^5.31.1" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, "node_modules/tiny-invariant": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", @@ -12960,7 +13529,6 @@ "version": "6.21.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "dev": true, "license": "MIT" }, "node_modules/unicode-canonical-property-names-ecmascript": { @@ -13308,6 +13876,20 @@ "node": ">=18" } }, + "node_modules/watchpack": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.1.tgz", + "integrity": "sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==", + "license": "MIT", + "peer": true, + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/webidl-conversions": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", @@ -13318,6 +13900,96 @@ "node": ">=12" } }, + "node_modules/webpack": { + "version": "5.105.4", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.105.4.tgz", + "integrity": "sha512-jTywjboN9aHxFlToqb0K0Zs9SbBoW4zRUlGzI2tYNxVYcEi/IPpn+Xi4ye5jTLvX2YeLuic/IvxNot+Q1jMoOw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/eslint-scope": "^3.7.7", + "@types/estree": "^1.0.8", + "@types/json-schema": "^7.0.15", + "@webassemblyjs/ast": "^1.14.1", + "@webassemblyjs/wasm-edit": "^1.14.1", + "@webassemblyjs/wasm-parser": "^1.14.1", + "acorn": "^8.16.0", + "acorn-import-phases": "^1.0.3", + "browserslist": "^4.28.1", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.20.0", + "es-module-lexer": "^2.0.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.11", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.3.1", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^4.3.3", + "tapable": "^2.3.0", + "terser-webpack-plugin": "^5.3.17", + "watchpack": "^2.5.1", + "webpack-sources": "^3.3.4" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-sources": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.4.tgz", + "integrity": "sha512-7tP1PdV4vF+lYPnkMR0jMY5/la2ub5Fc/8VQrrU+lXkiM6C4TjVfGw7iKfyhnTQOsD+6Q/iKw0eFciziRgD58Q==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack/node_modules/es-module-lexer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz", + "integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==", + "license": "MIT", + "peer": true + }, + "node_modules/webpack/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "license": "BSD-2-Clause", + "peer": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/webpack/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "license": "BSD-2-Clause", + "peer": true, + "engines": { + "node": ">=4.0" + } + }, "node_modules/whatwg-encoding": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", From befd1b3072400479225c61821164ddbf2f46388d Mon Sep 17 00:00:00 2001 From: AbuJulaybeeb Date: Wed, 25 Mar 2026 12:09:45 +0100 Subject: [PATCH 03/10] fix: resolve linting issues and manifest 404 --- .eslintrc.json | 24 +- .github/ISSUE_TEMPLATE/quality-gates.yml | 8 +- .github/branch-protection.md | 10 + .github/pull_request_template.md | 8 + .github/workflows/ci.yml | 20 +- .kiro/specs/form-management-system/design.md | 137 +++++---- .../form-management-system/requirements.md | 2 +- .kiro/specs/form-management-system/tasks.md | 278 +++++++++++------- ACCESSIBILITY_IMPLEMENTATION_GUIDE.md | 52 ++-- CONTRIBUTING.md | 12 + IMPLEMENTATION_SUMMARY.md | 28 ++ OFFLINE_MODE_README.md | 35 ++- README.md | 1 + lint-staged.config.js | 4 +- next.config.ts | 4 +- postcss.config.js | 2 +- postcss.config.ts | 2 +- {src/public => public}/manifest.json | 0 scripts/validate-ui.js | 36 +-- scripts/validate-web3.js | 38 +-- src/app/components/accessibility/README.md | 52 +++- src/app/globals.css | 28 +- src/components/pwa/AppUpdateManager.tsx | 2 +- src/components/pwa/NativeIntegrationLayer.tsx | 2 +- src/components/pwa/PWAManager.tsx | 2 +- src/form-management/README.md | 4 +- src/form-management/auto-save/README.md | 21 +- src/form-management/utils/README.md | 61 ++-- src/serviceWorker.ts | 16 +- src/styles/animations.css | 4 +- tailwind.config.js | 18 +- task.md | 4 + tsconfig.json | 25 +- vitest.config.ts | 2 +- 34 files changed, 574 insertions(+), 368 deletions(-) rename {src/public => public}/manifest.json (100%) diff --git a/.eslintrc.json b/.eslintrc.json index 50418fb7..8b67e894 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,15 +1,9 @@ -{ - "extends": [ - "next/core-web-vitals", - "next/typescript", - "prettier" - ], - "plugins": [ - "prettier" - ], - "rules": { - "@typescript-eslint/no-unused-vars": "off", - "@typescript-eslint/no-explicit-any": "off", - "prettier/prettier": "error" - } -} \ No newline at end of file +{ + "extends": ["next/core-web-vitals", "next/typescript", "prettier"], + "plugins": ["prettier"], + "rules": { + "@typescript-eslint/no-unused-vars": "off", + "@typescript-eslint/no-explicit-any": "off", + "prettier/prettier": "error" + } +} diff --git a/.github/ISSUE_TEMPLATE/quality-gates.yml b/.github/ISSUE_TEMPLATE/quality-gates.yml index 12991d0a..ff9f551d 100644 --- a/.github/ISSUE_TEMPLATE/quality-gates.yml +++ b/.github/ISSUE_TEMPLATE/quality-gates.yml @@ -1,7 +1,7 @@ -name: "PR Quality Gates / Governance" -description: "Work related to CI, branch protection, PR process, governance" -title: "[Governance] " -labels: ["frontend", "devops", "ci", "governance", "priority-high"] +name: 'PR Quality Gates / Governance' +description: 'Work related to CI, branch protection, PR process, governance' +title: '[Governance] ' +labels: ['frontend', 'devops', 'ci', 'governance', 'priority-high'] body: - type: markdown attributes: diff --git a/.github/branch-protection.md b/.github/branch-protection.md index 959489a1..649200f5 100644 --- a/.github/branch-protection.md +++ b/.github/branch-protection.md @@ -4,25 +4,31 @@ These are **GitHub repository settings** (not enforced by code). Configure them **Settings → Branches → Branch protection rules**. ## Protected branches + Create rules for: + - `main` - `develop` ## Required settings + Enable the following options: ### блок direct pushes + - ✅ **Restrict who can push to matching branches** (recommended) - ✅ **Do not allow force pushes** - ✅ **Do not allow deletions** ### Require PRs + - ✅ **Require a pull request before merging** - ✅ **Require approvals**: at least **1** (or **2** if desired) - ✅ **Dismiss stale approvals when new commits are pushed** - ✅ **Require conversation resolution before merging** ### Require checks + - ✅ **Require status checks to pass before merging** - ✅ Select required checks from `Frontend CI`: - `type-check` @@ -31,13 +37,16 @@ Enable the following options: - `test` ### Keep branch up to date + - ✅ **Require branches to be up to date before merging** ## PR must reference an issue + GitHub does not have a single built-in "require issue link" toggle for all repos. Recommended options: 1. **Process enforcement (lightweight)** + - Use `.github/pull_request_template.md` and require `Closes #` in the PR. 2. **Stronger enforcement (recommended)** @@ -45,5 +54,6 @@ Recommended options: - If you want this, we can add a small workflow using `actions/github-script`. ## Notes + - Repository admins can optionally be included or excluded from these requirements. - Configure the same rule set for both `main` and `develop` to avoid bypass paths. diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index aaf3f2ce..76c3c232 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,27 +1,35 @@ ## Summary + ## Related Issue + + Closes # ## Type of change + - [ ] Feature - [ ] Bug fix - [ ] Chore / Refactor - [ ] Docs ## Screenshots / Recording (if UI) + ## Testing + + - [ ] `npm run type-check` - [ ] `npm run lint` - [ ] `npm run test` - [ ] `npm run build` ## Quality gate checklist + - [ ] CI checks pass (Frontend CI) - [ ] At least 1–2 approvals (per branch protection rules) - [ ] Branch is up-to-date with the base branch diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9e3050f8..01b9c82b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,8 +15,8 @@ jobs: - name: Set up Node.js uses: actions/setup-node@v4 with: - node-version: "20" - cache: "npm" + node-version: '20' + cache: 'npm' - name: Install dependencies run: npm ci @@ -32,8 +32,8 @@ jobs: - name: Set up Node.js uses: actions/setup-node@v4 with: - node-version: "20" - cache: "npm" + node-version: '20' + cache: 'npm' - name: Install dependencies run: npm ci @@ -49,8 +49,8 @@ jobs: - name: Set up Node.js uses: actions/setup-node@v4 with: - node-version: "20" - cache: "npm" + node-version: '20' + cache: 'npm' - name: Install dependencies run: npm ci @@ -70,8 +70,8 @@ jobs: - name: Set up Node.js uses: actions/setup-node@v4 with: - node-version: "20" - cache: "npm" + node-version: '20' + cache: 'npm' - name: Install dependencies run: npm ci @@ -99,8 +99,8 @@ jobs: - name: Set up Node.js uses: actions/setup-node@v4 with: - node-version: "20" - cache: "npm" + node-version: '20' + cache: 'npm' - name: Install dependencies run: npm ci diff --git a/.kiro/specs/form-management-system/design.md b/.kiro/specs/form-management-system/design.md index a150e059..c9ad5750 100644 --- a/.kiro/specs/form-management-system/design.md +++ b/.kiro/specs/form-management-system/design.md @@ -17,25 +17,25 @@ graph TB FW[Form Wizard] UI[UI Components] end - + subgraph "Business Logic Layer" VE[Validation Engine] FSM[Form State Manager] CP[Configuration Parser] AT[Analytics Tracker] end - + subgraph "Data Layer" ASM[Auto Save Manager] DS[Data Store] LS[Local Storage] end - + subgraph "External" API[Validation APIs] Analytics[Analytics Service] end - + FB --> FSM FB --> VE FB --> CP @@ -45,12 +45,12 @@ graph TB ASM --> DS ASM --> LS AT --> Analytics - + classDef presentation fill:#e1f5fe classDef business fill:#f3e5f5 classDef data fill:#e8f5e8 classDef external fill:#fff3e0 - + class FB,FW,UI presentation class VE,FSM,CP,AT business class ASM,DS,LS data @@ -224,18 +224,18 @@ interface FormConfiguration { } // Field Type Definitions -type FieldType = - | 'text' - | 'number' - | 'email' - | 'password' - | 'select' - | 'checkbox' - | 'radio' - | 'textarea' - | 'file' - | 'date' - | 'time' +type FieldType = + | 'text' + | 'number' + | 'email' + | 'password' + | 'select' + | 'checkbox' + | 'radio' + | 'textarea' + | 'file' + | 'date' + | 'time' | 'datetime-local'; // Validation Configuration @@ -298,7 +298,7 @@ sequenceDiagram participant ValidationEngine participant AutoSaveManager participant Analytics - + User->>FormBuilder: Interact with field FormBuilder->>StateManager: Update field value StateManager->>ValidationEngine: Validate field @@ -313,245 +313,245 @@ The data flow ensures that all components stay synchronized while maintaining cl ## Correctness Properties -*A property is a characteristic or behavior that should hold true across all valid executions of a system-essentially, a formal statement about what the system should do. Properties serve as the bridge between human-readable specifications and machine-verifiable correctness guarantees.* +_A property is a characteristic or behavior that should hold true across all valid executions of a system-essentially, a formal statement about what the system should do. Properties serve as the bridge between human-readable specifications and machine-verifiable correctness guarantees._ ### Property 1: Complete Form Rendering -*For any* valid Form_Configuration, the Form_Builder should render a complete form containing all specified fields with their correct types and properties. +_For any_ valid Form_Configuration, the Form_Builder should render a complete form containing all specified fields with their correct types and properties. **Validates: Requirements 1.1, 1.2** ### Property 2: Conditional Field Visibility -*For any* form with field dependencies, when a dependent field's value changes, all fields that depend on it should update their visibility according to the dependency rules. +_For any_ form with field dependencies, when a dependent field's value changes, all fields that depend on it should update their visibility according to the dependency rules. **Validates: Requirements 1.3, 1.5** ### Property 3: Configuration Styling Application -*For any* Form_Configuration with styling and layout options, the rendered form should apply all specified styling and layout configurations to the appropriate elements. +_For any_ Form_Configuration with styling and layout options, the rendered form should apply all specified styling and layout configurations to the appropriate elements. **Validates: Requirements 1.4** ### Property 4: Validation Execution -*For any* form field with validation rules, validation should execute on blur, change, and submit events, returning appropriate validation results for both synchronous and asynchronous rules. +_For any_ form field with validation rules, validation should execute on blur, change, and submit events, returning appropriate validation results for both synchronous and asynchronous rules. **Validates: Requirements 2.1, 2.2, 2.3, 2.4** ### Property 5: Custom Validation Context -*For any* custom validation function, it should receive access to the complete current form state when executed. +_For any_ custom validation function, it should receive access to the complete current form state when executed. **Validates: Requirements 2.5** ### Property 6: Validation Feedback Display -*For any* validation result (success or failure), the system should display appropriate visual feedback with configurable positioning and styling. +_For any_ validation result (success or failure), the system should display appropriate visual feedback with configurable positioning and styling. **Validates: Requirements 2.6, 2.7** ### Property 7: Auto-Save Triggering -*For any* form with auto-save enabled, data should be automatically saved at configured intervals and on field blur events. +_For any_ form with auto-save enabled, data should be automatically saved at configured intervals and on field blur events. **Validates: Requirements 3.1, 3.3** ### Property 8: Draft Data Recovery -*For any* form with saved draft data, when a user returns to the form, the system should restore all previously saved field values and state. +_For any_ form with saved draft data, when a user returns to the form, the system should restore all previously saved field values and state. **Validates: Requirements 3.2** ### Property 9: Offline Save Management -*For any* auto-save operation that fails due to network connectivity, the system should queue the save and retry when connectivity is restored. +_For any_ auto-save operation that fails due to network connectivity, the system should queue the save and retry when connectivity is restored. **Validates: Requirements 3.4** ### Property 10: Save Status Indication -*For any* auto-save operation, the system should display appropriate visual indicators reflecting the current save status (saving, saved, error). +_For any_ auto-save operation, the system should display appropriate visual indicators reflecting the current save status (saving, saved, error). **Validates: Requirements 3.5** ### Property 11: Draft Cleanup -*For any* form that is successfully submitted, all associated draft data should be cleared from storage. +_For any_ form that is successfully submitted, all associated draft data should be cleared from storage. **Validates: Requirements 3.6** ### Property 12: Storage Quota Management -*For any* storage system approaching quota limits, the Auto_Save_Manager should remove oldest drafts to maintain storage within limits. +_For any_ storage system approaching quota limits, the Auto_Save_Manager should remove oldest drafts to maintain storage within limits. **Validates: Requirements 3.7** ### Property 13: Wizard Step Navigation -*For any* multi-step form, users should be able to navigate between steps using next/previous controls, with navigation blocked if the current step is invalid. +_For any_ multi-step form, users should be able to navigate between steps using next/previous controls, with navigation blocked if the current step is invalid. **Validates: Requirements 4.1, 4.2** ### Property 14: Step Data Preservation -*For any* multi-step form navigation, all entered data should be preserved when moving between steps. +_For any_ multi-step form navigation, all entered data should be preserved when moving between steps. **Validates: Requirements 4.3** ### Property 15: Progress Indication -*For any* multi-step form, progress indicators should accurately reflect the current step and overall completion status. +_For any_ multi-step form, progress indicators should accurately reflect the current step and overall completion status. **Validates: Requirements 4.4** ### Property 16: Conditional Step Routing -*For any* multi-step form with conditional routing rules, navigation should follow the correct path based on previous answers. +_For any_ multi-step form with conditional routing rules, navigation should follow the correct path based on previous answers. **Validates: Requirements 4.5** ### Property 17: Non-Linear Step Access -*For any* multi-step form, users should be able to jump directly to any previously completed step. +_For any_ multi-step form, users should be able to jump directly to any previously completed step. **Validates: Requirements 4.6** ### Property 18: Final Step Submission -*For any* multi-step form on the final step, form submission functionality should be available and functional. +_For any_ multi-step form on the final step, form submission functionality should be available and functional. **Validates: Requirements 4.7** ### Property 19: Comprehensive Analytics Tracking -*For any* form interaction (start, field focus/blur/change, abandonment), the Analytics_Tracker should record the appropriate event data with timestamps and context. +_For any_ form interaction (start, field focus/blur/change, abandonment), the Analytics_Tracker should record the appropriate event data with timestamps and context. **Validates: Requirements 5.1, 5.2, 5.3** ### Property 20: Time Measurement Tracking -*For any* form step or field interaction, the system should accurately measure and record time spent. +_For any_ form step or field interaction, the system should accurately measure and record time spent. **Validates: Requirements 5.4** ### Property 21: Analytics Calculations -*For any* set of form analytics data, the system should correctly calculate completion rates and identify bottleneck fields. +_For any_ set of form analytics data, the system should correctly calculate completion rates and identify bottleneck fields. **Validates: Requirements 5.5** ### Property 22: Analytics Reporting -*For any* collected analytics data, it should be accessible through the reporting interface in aggregated form. +_For any_ collected analytics data, it should be accessible through the reporting interface in aggregated form. **Validates: Requirements 5.6** ### Property 23: Privacy Mode Anonymization -*For any* analytics data collected when privacy mode is enabled, all personally identifiable information should be anonymized. +_For any_ analytics data collected when privacy mode is enabled, all personally identifiable information should be anonymized. **Validates: Requirements 5.7** ### Property 24: Configuration Parsing -*For any* valid Form_Configuration JSON, the Configuration_Parser should successfully parse it into the correct internal form structure. +_For any_ valid Form_Configuration JSON, the Configuration_Parser should successfully parse it into the correct internal form structure. **Validates: Requirements 6.1** ### Property 25: Configuration Validation -*For any* invalid Form_Configuration, the Configuration_Parser should return descriptive validation errors identifying the specific issues. +_For any_ invalid Form_Configuration, the Configuration_Parser should return descriptive validation errors identifying the specific issues. **Validates: Requirements 6.2** ### Property 26: Complex Structure Parsing -*For any* Form_Configuration with nested field groups and complex layouts, the parser should correctly handle the nested structure. +_For any_ Form_Configuration with nested field groups and complex layouts, the parser should correctly handle the nested structure. **Validates: Requirements 6.3** ### Property 27: Configuration Formatting -*For any* internal Form_Configuration object, the Pretty_Printer should format it into valid JSON. +_For any_ internal Form_Configuration object, the Pretty_Printer should format it into valid JSON. **Validates: Requirements 6.4** ### Property 28: Configuration Round-Trip -*For any* valid Form_Configuration object, parsing then printing then parsing should produce an equivalent object. +_For any_ valid Form_Configuration object, parsing then printing then parsing should produce an equivalent object. **Validates: Requirements 6.5** ### Property 29: Comprehensive State Management -*For any* form field value or validation state change, the Form_State_Manager should maintain accurate current values and validation status for all fields and the overall form. +_For any_ form field value or validation state change, the Form_State_Manager should maintain accurate current values and validation status for all fields and the overall form. **Validates: Requirements 7.1, 7.2** ### Property 30: Cascading State Updates -*For any* field value change, the Form_State_Manager should update all dependent field visibility and validation states accordingly. +_For any_ field value change, the Form_State_Manager should update all dependent field visibility and validation states accordingly. **Validates: Requirements 7.3** ### Property 31: Programmatic State Control -*For any* programmatic state manipulation through Form_State_Manager methods, field values and validation states should update correctly. +_For any_ programmatic state manipulation through Form_State_Manager methods, field values and validation states should update correctly. **Validates: Requirements 7.4** ### Property 32: Form Reset Functionality -*For any* form reset operation, all field data and validation states should be cleared to their initial state. +_For any_ form reset operation, all field data and validation states should be cleared to their initial state. **Validates: Requirements 7.5** ### Property 33: State Change Events -*For any* form state change, appropriate events should be emitted to enable reactive updates. +_For any_ form state change, appropriate events should be emitted to enable reactive updates. **Validates: Requirements 7.6** ### Property 34: Accessibility Markup Generation -*For any* generated form, all elements should include proper ARIA labels, descriptions, and semantic HTML structure. +_For any_ generated form, all elements should include proper ARIA labels, descriptions, and semantic HTML structure. **Validates: Requirements 8.1, 8.6** ### Property 35: Keyboard Navigation Support -*For any* form element, keyboard navigation should work correctly with customizable focus indicators and proper tab order. +_For any_ form element, keyboard navigation should work correctly with customizable focus indicators and proper tab order. **Validates: Requirements 8.2, 8.5** ### Property 36: Screen Reader Error Announcements -*For any* validation error, the system should make appropriate announcements to screen readers. +_For any_ validation error, the system should make appropriate announcements to screen readers. **Validates: Requirements 8.3** ### Property 37: High Contrast Mode Support -*For any* form in high contrast mode, all elements should display with appropriate contrast and visibility. +_For any_ form in high contrast mode, all elements should display with appropriate contrast and visibility. **Validates: Requirements 8.4** ### Property 38: Performance Optimizations -*For any* large form, the system should implement virtual scrolling, lazy loading, and debouncing to maintain responsive performance. +_For any_ large form, the system should implement virtual scrolling, lazy loading, and debouncing to maintain responsive performance. **Validates: Requirements 9.1, 9.2, 9.3** ### Property 39: Data Compression -*For any* draft data saved to storage, the Auto_Save_Manager should compress the data to minimize storage usage. +_For any_ draft data saved to storage, the Auto_Save_Manager should compress the data to minimize storage usage. **Validates: Requirements 9.5** ### Property 40: Progressive Enhancement -*For any* form, core functionality should work without JavaScript through progressive enhancement. +_For any_ form, core functionality should work without JavaScript through progressive enhancement. **Validates: Requirements 9.6** @@ -616,16 +616,15 @@ Each property test references its corresponding design document property: describe('Form Management System Properties', () => { it('Property 1: Complete Form Rendering', () => { // Feature: form-management-system, Property 1: Complete Form Rendering - fc.assert(fc.property( - formConfigurationArbitrary(), - (config) => { + fc.assert( + fc.property(formConfigurationArbitrary(), (config) => { const form = formBuilder.render(config); - return config.fields.every(field => - form.hasField(field.id) && - form.getFieldType(field.id) === field.type + return config.fields.every( + (field) => form.hasField(field.id) && form.getFieldType(field.id) === field.type, ); - } - ), { numRuns: 100 }); + }), + { numRuns: 100 }, + ); }); }); ``` @@ -638,4 +637,4 @@ describe('Form Management System Properties', () => { - **Performance Tests**: Load testing for large forms and high-frequency auto-save operations - **Accessibility Tests**: Automated accessibility testing with axe-core integration -The testing strategy ensures both functional correctness through property verification and practical usability through targeted unit and integration testing. \ No newline at end of file +The testing strategy ensures both functional correctness through property verification and practical usability through targeted unit and integration testing. diff --git a/.kiro/specs/form-management-system/requirements.md b/.kiro/specs/form-management-system/requirements.md index 88f62361..f2157b94 100644 --- a/.kiro/specs/form-management-system/requirements.md +++ b/.kiro/specs/form-management-system/requirements.md @@ -136,4 +136,4 @@ The Form Management System provides a comprehensive solution for creating, manag 3. WHEN rendering large forms, THE Form_Builder SHALL debounce validation and auto-save operations 4. THE Form_Builder SHALL minimize re-renders by using efficient state update strategies 5. THE Auto_Save_Manager SHALL compress draft data before storage to minimize storage usage -6. THE Form_Builder SHALL support progressive enhancement for core functionality without JavaScript \ No newline at end of file +6. THE Form_Builder SHALL support progressive enhancement for core functionality without JavaScript diff --git a/.kiro/specs/form-management-system/tasks.md b/.kiro/specs/form-management-system/tasks.md index c9f2602a..e13a3525 100644 --- a/.kiro/specs/form-management-system/tasks.md +++ b/.kiro/specs/form-management-system/tasks.md @@ -9,6 +9,7 @@ The implementation follows a bottom-up approach, starting with core data structu ## Tasks - [x] 1. Set up project structure and core types + - Create TypeScript project configuration with strict type checking - Define core interfaces and type definitions from design document - Set up testing framework with Jest and fast-check for property-based testing @@ -16,360 +17,435 @@ The implementation follows a bottom-up approach, starting with core data structu - _Requirements: All requirements depend on proper type definitions_ - [x] 2. Implement Configuration Parser and validation + - [x] 2.1 Create Form Configuration schema validation + - Implement JSON schema validation for FormConfiguration objects - Add validation for field types, required properties, and nested structures - Create descriptive error messages for invalid configurations - _Requirements: 6.1, 6.2, 6.3_ - - - [ ]* 2.2 Write property test for Configuration Parser + + - [ ]\* 2.2 Write property test for Configuration Parser + - **Property 24: Configuration Parsing** - **Validates: Requirements 6.1** - - - [ ]* 2.3 Write property test for Configuration Validation + + - [ ]\* 2.3 Write property test for Configuration Validation + - **Property 25: Configuration Validation** - **Validates: Requirements 6.2** - + - [x] 2.4 Implement Pretty Printer for configurations + - Create formatter to convert internal configuration objects back to JSON - Ensure proper formatting and structure preservation - _Requirements: 6.4_ - - - [ ]* 2.5 Write property test for Configuration Round-Trip + + - [ ]\* 2.5 Write property test for Configuration Round-Trip - **Property 28: Configuration Round-Trip** - **Validates: Requirements 6.5** - [x] 3. Build Form State Manager + - [x] 3.1 Implement core state management functionality + - Create FormState interface implementation with values, validation, and metadata tracking - Implement field value updates with change detection - Add subscription system for state change notifications - _Requirements: 7.1, 7.2, 7.6_ - - - [ ]* 3.2 Write property test for Comprehensive State Management + + - [ ]\* 3.2 Write property test for Comprehensive State Management + - **Property 29: Comprehensive State Management** - **Validates: Requirements 7.1, 7.2** - + - [x] 3.3 Add programmatic state control methods + - Implement methods for setting field values and validation states - Add form reset functionality to clear all data and states - _Requirements: 7.4, 7.5_ - - - [ ]* 3.4 Write property test for Form Reset Functionality + + - [ ]\* 3.4 Write property test for Form Reset Functionality + - **Property 32: Form Reset Functionality** - **Validates: Requirements 7.5** - + - [x] 3.5 Implement cascading state updates + - Add dependency tracking for field visibility and validation updates - Implement conditional logic evaluation for dependent fields - _Requirements: 7.3_ - - - [ ]* 3.6 Write property test for Cascading State Updates + + - [ ]\* 3.6 Write property test for Cascading State Updates - **Property 30: Cascading State Updates** - **Validates: Requirements 7.3** - [x] 4. Create Validation Engine + - [x] 4.1 Implement synchronous validation system + - Create validation rule processors for built-in rules (required, email, length, pattern) - Add field-level validation with immediate feedback - Implement form-level validation for submission - _Requirements: 2.1, 2.3, 2.4_ - - - [ ]* 4.2 Write property test for Validation Execution + + - [ ]\* 4.2 Write property test for Validation Execution + - **Property 4: Validation Execution** - **Validates: Requirements 2.1, 2.2, 2.3, 2.4** - + - [x] 4.3 Add asynchronous validation support + - Implement async validation with loading states and timeout handling - Add retry mechanisms for failed async validations - _Requirements: 2.2_ - + - [x] 4.4 Implement custom validation functions + - Add support for custom validation rules with form state access - Create validation function registry and execution context - _Requirements: 2.5_ - - - [ ]* 4.5 Write property test for Custom Validation Context + + - [ ]\* 4.5 Write property test for Custom Validation Context + - **Property 5: Custom Validation Context** - **Validates: Requirements 2.5** - + - [x] 4.6 Create validation feedback display system + - Implement error message rendering with configurable positioning - Add success feedback and visual confirmation states - _Requirements: 2.6, 2.7_ - - - [ ]* 4.7 Write property test for Validation Feedback Display + + - [ ]\* 4.7 Write property test for Validation Feedback Display - **Property 6: Validation Feedback Display** - **Validates: Requirements 2.6, 2.7** - [x] 5. Checkpoint - Core validation and state management complete + - Ensure all tests pass, ask the user if questions arise. - [x] 6. Build Auto-Save Manager + - [x] 6.1 Implement basic auto-save functionality + - Create automatic save triggers at configurable intervals - Add field blur event save triggers - Implement draft data storage with timestamps and metadata - _Requirements: 3.1, 3.3_ - - - [ ]* 6.2 Write property test for Auto-Save Triggering + + - [ ]\* 6.2 Write property test for Auto-Save Triggering + - **Property 7: Auto-Save Triggering** - **Validates: Requirements 3.1, 3.3** - + - [x] 6.3 Add draft data recovery system + - Implement draft loading and restoration on form initialization - Add data integrity validation for loaded drafts - _Requirements: 3.2_ - - - [ ]* 6.4 Write property test for Draft Data Recovery + + - [ ]\* 6.4 Write property test for Draft Data Recovery + - **Property 8: Draft Data Recovery** - **Validates: Requirements 3.2** - + - [x] 6.5 Implement offline save management + - Add save queue for failed operations with retry logic - Implement network connectivity detection and recovery - _Requirements: 3.4_ - - - [ ]* 6.6 Write property test for Offline Save Management + + - [ ]\* 6.6 Write property test for Offline Save Management + - **Property 9: Offline Save Management** - **Validates: Requirements 3.4** - + - [x] 6.7 Create save status indication system + - Implement visual indicators for save states (saving, saved, error) - Add status change notifications and callbacks - _Requirements: 3.5_ - - - [ ]* 6.8 Write property test for Save Status Indication + + - [ ]\* 6.8 Write property test for Save Status Indication + - **Property 10: Save Status Indication** - **Validates: Requirements 3.5** - + - [x] 6.9 Add storage management features + - Implement draft cleanup after successful submission - Add storage quota management with oldest-first cleanup - _Requirements: 3.6, 3.7_ - - - [ ]* 6.10 Write property test for Draft Cleanup + + - [ ]\* 6.10 Write property test for Draft Cleanup + - **Property 11: Draft Cleanup** - **Validates: Requirements 3.6** - - - [ ]* 6.11 Write property test for Storage Quota Management + + - [ ]\* 6.11 Write property test for Storage Quota Management - **Property 12: Storage Quota Management** - **Validates: Requirements 3.7** - [~] 7. Implement Form Builder + - [ ] 7.1 Create dynamic form rendering system + - Implement form generation from FormConfiguration objects - Add support for all field types (text, number, email, password, select, checkbox, radio, textarea, file) - Create field component factory and rendering pipeline - _Requirements: 1.1, 1.2_ - - - [ ]* 7.2 Write property test for Complete Form Rendering + + - [ ]\* 7.2 Write property test for Complete Form Rendering + - **Property 1: Complete Form Rendering** - **Validates: Requirements 1.1, 1.2** - + - [ ] 7.3 Add conditional field visibility system + - Implement field dependency tracking and evaluation - Add dynamic show/hide logic based on field values - Create conditional logic processor for complex rules - _Requirements: 1.3, 1.5_ - - - [ ]* 7.4 Write property test for Conditional Field Visibility + + - [ ]\* 7.4 Write property test for Conditional Field Visibility + - **Property 2: Conditional Field Visibility** - **Validates: Requirements 1.3, 1.5** - + - [ ] 7.5 Implement styling and layout application + - Add field-level styling from configuration - Implement layout options (single-column, two-column, grid, custom) - Create responsive layout system - _Requirements: 1.4_ - - - [ ]* 7.6 Write property test for Configuration Styling Application + + - [ ]\* 7.6 Write property test for Configuration Styling Application - **Property 3: Configuration Styling Application** - **Validates: Requirements 1.4** - [~] 8. Create Form Wizard for multi-step navigation + - [ ] 8.1 Implement step navigation system + - Create wizard step management with next/previous controls - Add step validation before navigation - Implement step completion tracking - _Requirements: 4.1, 4.2_ - - - [ ]* 8.2 Write property test for Wizard Step Navigation + + - [ ]\* 8.2 Write property test for Wizard Step Navigation + - **Property 13: Wizard Step Navigation** - **Validates: Requirements 4.1, 4.2** - + - [ ] 8.3 Add data preservation across steps + - Implement state preservation during step navigation - Add step data validation and persistence - _Requirements: 4.3_ - - - [ ]* 8.4 Write property test for Step Data Preservation + + - [ ]\* 8.4 Write property test for Step Data Preservation + - **Property 14: Step Data Preservation** - **Validates: Requirements 4.3** - + - [ ] 8.5 Create progress indication system + - Implement progress indicators with current step and completion status - Add visual progress tracking and step status display - _Requirements: 4.4_ - - - [ ]* 8.6 Write property test for Progress Indication + + - [ ]\* 8.6 Write property test for Progress Indication + - **Property 15: Progress Indication** - **Validates: Requirements 4.4** - + - [ ] 8.7 Add conditional step routing + - Implement conditional navigation based on previous answers - Add dynamic step path calculation - _Requirements: 4.5_ - - - [ ]* 8.8 Write property test for Conditional Step Routing + + - [ ]\* 8.8 Write property test for Conditional Step Routing + - **Property 16: Conditional Step Routing** - **Validates: Requirements 4.5** - + - [ ] 8.9 Implement non-linear step access + - Add ability to jump to previously completed steps - Implement step accessibility validation - _Requirements: 4.6_ - - - [ ]* 8.10 Write property test for Non-Linear Step Access + + - [ ]\* 8.10 Write property test for Non-Linear Step Access + - **Property 17: Non-Linear Step Access** - **Validates: Requirements 4.6** - + - [ ] 8.11 Add final step submission functionality + - Implement form submission on final step - Add submission validation and processing - _Requirements: 4.7_ - - - [ ]* 8.12 Write property test for Final Step Submission + + - [ ]\* 8.12 Write property test for Final Step Submission - **Property 18: Final Step Submission** - **Validates: Requirements 4.7** - [~] 9. Checkpoint - Core form functionality complete + - Ensure all tests pass, ask the user if questions arise. - [~] 10. Build Analytics Tracker + - [ ] 10.1 Implement basic analytics tracking + - Create event tracking for form start, field interactions, and abandonment - Add timestamp and context data collection - Implement session tracking and user identification - _Requirements: 5.1, 5.2, 5.3_ - - - [ ]* 10.2 Write property test for Comprehensive Analytics Tracking + + - [ ]\* 10.2 Write property test for Comprehensive Analytics Tracking + - **Property 19: Comprehensive Analytics Tracking** - **Validates: Requirements 5.1, 5.2, 5.3** - + - [ ] 10.3 Add time measurement tracking + - Implement time tracking for form steps and field interactions - Add duration calculation and performance metrics - _Requirements: 5.4_ - - - [ ]* 10.4 Write property test for Time Measurement Tracking + + - [ ]\* 10.4 Write property test for Time Measurement Tracking + - **Property 20: Time Measurement Tracking** - **Validates: Requirements 5.4** - + - [ ] 10.5 Create analytics calculations system + - Implement completion rate calculations - Add bottleneck field identification algorithms - Create aggregated metrics processing - _Requirements: 5.5_ - - - [ ]* 10.6 Write property test for Analytics Calculations + + - [ ]\* 10.6 Write property test for Analytics Calculations + - **Property 21: Analytics Calculations** - **Validates: Requirements 5.5** - + - [ ] 10.7 Build analytics reporting interface + - Create reporting API for accessing aggregated analytics data - Add data export and visualization support - _Requirements: 5.6_ - - - [ ]* 10.8 Write property test for Analytics Reporting + + - [ ]\* 10.8 Write property test for Analytics Reporting + - **Property 22: Analytics Reporting** - **Validates: Requirements 5.6** - + - [ ] 10.9 Implement privacy mode and data anonymization + - Add privacy mode toggle with data anonymization - Implement PII detection and removal algorithms - _Requirements: 5.7_ - - - [ ]* 10.10 Write property test for Privacy Mode Anonymization + + - [ ]\* 10.10 Write property test for Privacy Mode Anonymization - **Property 23: Privacy Mode Anonymization** - **Validates: Requirements 5.7** - [~] 11. Add accessibility and user experience features + - [ ] 11.1 Implement accessibility markup generation + - Add ARIA labels, descriptions, and semantic HTML structure - Implement proper form labeling and field associations - _Requirements: 8.1, 8.6_ - - - [ ]* 11.2 Write property test for Accessibility Markup Generation + + - [ ]\* 11.2 Write property test for Accessibility Markup Generation + - **Property 34: Accessibility Markup Generation** - **Validates: Requirements 8.1, 8.6** - + - [ ] 11.3 Add keyboard navigation support + - Implement keyboard navigation with customizable focus indicators - Add proper tab order and focus management - _Requirements: 8.2, 8.5_ - - - [ ]* 11.4 Write property test for Keyboard Navigation Support + + - [ ]\* 11.4 Write property test for Keyboard Navigation Support + - **Property 35: Keyboard Navigation Support** - **Validates: Requirements 8.2, 8.5** - + - [ ] 11.5 Create screen reader error announcements + - Implement error announcements for screen readers - Add live regions for dynamic content updates - _Requirements: 8.3_ - - - [ ]* 11.6 Write property test for Screen Reader Error Announcements + + - [ ]\* 11.6 Write property test for Screen Reader Error Announcements + - **Property 36: Screen Reader Error Announcements** - **Validates: Requirements 8.3** - + - [ ] 11.7 Add high contrast mode support + - Implement high contrast mode with appropriate styling - Add contrast validation and accessibility compliance - _Requirements: 8.4_ - - - [ ]* 11.8 Write property test for High Contrast Mode Support + + - [ ]\* 11.8 Write property test for High Contrast Mode Support - **Property 37: High Contrast Mode Support** - **Validates: Requirements 8.4** - [~] 12. Implement performance optimizations + - [ ] 12.1 Add performance optimization features + - Implement virtual scrolling for large forms - Add lazy loading for validation rules and field components - Create debouncing for validation and auto-save operations - Add efficient state update strategies to minimize re-renders - _Requirements: 9.1, 9.2, 9.3, 9.4_ - - - [ ]* 12.2 Write property test for Performance Optimizations + + - [ ]\* 12.2 Write property test for Performance Optimizations + - **Property 38: Performance Optimizations** - **Validates: Requirements 9.1, 9.2, 9.3** - + - [ ] 12.3 Add data compression for storage + - Implement draft data compression before storage - Add compression algorithms optimized for form data - _Requirements: 9.5_ - - - [ ]* 12.4 Write property test for Data Compression + + - [ ]\* 12.4 Write property test for Data Compression + - **Property 39: Data Compression** - **Validates: Requirements 9.5** - + - [ ] 12.5 Implement progressive enhancement + - Add core functionality that works without JavaScript - Create fallback mechanisms for enhanced features - _Requirements: 9.6_ - - - [ ]* 12.6 Write property test for Progressive Enhancement + + - [ ]\* 12.6 Write property test for Progressive Enhancement - **Property 40: Progressive Enhancement** - **Validates: Requirements 9.6** - [~] 13. Integration and system wiring + - [ ] 13.1 Wire all components together + - Integrate Form Builder with State Manager and Validation Engine - Connect Auto-Save Manager with Form State Manager - Wire Analytics Tracker to all form interactions - Create main FormManagementSystem class that orchestrates all components - _Requirements: All requirements - system integration_ - - - [ ]* 13.2 Write integration tests for complete workflows + + - [ ]\* 13.2 Write integration tests for complete workflows - Test end-to-end form creation, filling, validation, and submission - Test multi-step form navigation with auto-save and analytics - Test error handling and recovery scenarios @@ -387,4 +463,4 @@ The implementation follows a bottom-up approach, starting with core data structu - Property tests validate universal correctness properties from the design document - Checkpoints ensure incremental validation and provide opportunities for user feedback - The implementation uses TypeScript for type safety and better development experience -- All components are designed to work together while maintaining clear separation of concerns \ No newline at end of file +- All components are designed to work together while maintaining clear separation of concerns diff --git a/ACCESSIBILITY_IMPLEMENTATION_GUIDE.md b/ACCESSIBILITY_IMPLEMENTATION_GUIDE.md index 3b6aaa3d..0fa8a9e6 100644 --- a/ACCESSIBILITY_IMPLEMENTATION_GUIDE.md +++ b/ACCESSIBILITY_IMPLEMENTATION_GUIDE.md @@ -74,7 +74,10 @@ import { AccessibleError } from '@/app/components/accessibility/ScreenReaderOpti
)} -
+; ``` ### Modals/Dialogs @@ -100,12 +103,7 @@ function Modal({ isOpen, onClose, title, children }) { const containerRef = useFocusTrap(isOpen); return ( -
+
{children}
@@ -118,7 +116,7 @@ function Modal({ isOpen, onClose, title, children }) { ```tsx import { AccessibleLoading } from '@/app/components/accessibility/ScreenReaderOptimizer'; - +; ``` ### Progress Indicators @@ -126,12 +124,7 @@ import { AccessibleLoading } from '@/app/components/accessibility/ScreenReaderOp ```tsx import { AccessibleProgress } from '@/app/components/accessibility/ScreenReaderOptimizer'; - +; ``` ### Announcements @@ -190,11 +183,13 @@ function MyComponent() { ### Automated Testing 1. **Run Accessibility Tester** + - Click the green button (bottom-right) - Click "Run Accessibility Check" - Review and fix all critical and serious issues 2. **Check Color Contrast** + - Click the purple button (middle-right) - Click "Check Page Contrast" - Fix any failing contrast ratios @@ -207,17 +202,20 @@ function MyComponent() { ### Manual Testing 1. **Keyboard Navigation** + - Unplug your mouse - Navigate entire site using only keyboard - Verify all interactive elements are reachable - Check focus indicators are visible 2. **Screen Reader Testing** + - **Windows**: NVDA (free) or JAWS - **Mac**: VoiceOver (built-in) - **Mobile**: TalkBack (Android) or VoiceOver (iOS) - + Test checklist: + - [ ] All content is announced - [ ] Form labels are read correctly - [ ] Buttons have clear names @@ -226,6 +224,7 @@ function MyComponent() { - [ ] Status messages are announced 3. **Zoom Testing** + - Zoom to 200% (Ctrl/Cmd + +) - Verify all content is readable - Check for horizontal scrolling @@ -242,6 +241,7 @@ function MyComponent() { **Problem**: Images without alt attributes **Solution**: + ```tsx // Decorative image @@ -254,6 +254,7 @@ function MyComponent() { **Problem**: Inputs without associated labels **Solution**: + ```tsx // Option 1: Explicit label @@ -273,21 +274,32 @@ function MyComponent() { **Problem**: Text doesn't meet 4.5:1 contrast ratio **Solution**: + ```css /* Bad: 2.5:1 contrast */ -.text { color: #999; background: #fff; } +.text { + color: #999; + background: #fff; +} /* Good: 4.6:1 contrast */ -.text { color: #767676; background: #fff; } +.text { + color: #767676; + background: #fff; +} /* Better: 7:1 contrast */ -.text { color: #595959; background: #fff; } +.text { + color: #595959; + background: #fff; +} ``` ### Issue: Keyboard Trap **Problem**: Focus gets stuck in a component **Solution**: + ```tsx import { useFocusTrap } from '@/hooks/useAccessibility'; @@ -308,6 +320,7 @@ useEffect(() => { **Problem**: Can't see which element has focus **Solution**: + ```css /* Global focus styles already added in globals.css */ *:focus-visible { @@ -398,6 +411,7 @@ useEffect(() => { ## Support For questions or issues: + 1. Check the README in `src/app/components/accessibility/` 2. Review examples in `src/app/components/accessibility/examples/` 3. Test on the demo page at `/accessibility-demo` diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a71783d1..f4ac9e13 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -3,6 +3,7 @@ Thanks for contributing to TeachLink. ## Branching & workflow + - **Do not push directly** to protected branches (`main`, `develop`). - Create a feature branch from `develop` (preferred) or `main`: - `feat/` @@ -10,21 +11,27 @@ Thanks for contributing to TeachLink. - `chore/` ## Assignment required + Before opening a PR, ensure the issue is assigned to you. ## Pull request requirements (quality gates) + Your PR will be blocked from merging unless it meets the following: 1. **CI must pass** + - Required checks: `type-check`, `lint`, `build`, `test` (GitHub Actions: **Frontend CI**) 2. **Approvals required** + - Minimum **1–2 approvals** (as configured in branch protection rules). 3. **Branch must be up to date** + - Update your branch with the target branch before merge (no stale merge). 4. **Conversations resolved** + - All review conversations must be resolved before merge. 5. **Issue must be referenced** @@ -32,22 +39,27 @@ Your PR will be blocked from merging unless it meets the following: - `Close #` / `Closes #` / `Fixes #` ## Local checks (run before pushing) + - `npm run type-check` - `npm run lint` - `npm run test` - `npm run build` ## PR description format + Use the PR template (auto-applied). Ensure it includes: + - Summary of changes - Testing notes - `Close #` ## Code standards + - Keep changes small and focused. - No console errors. - Use `lucide-react` icons for UI. - Keep components accessible and responsive. ## Security + Do not commit secrets. Use `.env.local` for local environment variables. diff --git a/IMPLEMENTATION_SUMMARY.md b/IMPLEMENTATION_SUMMARY.md index 233920db..4a268d7a 100644 --- a/IMPLEMENTATION_SUMMARY.md +++ b/IMPLEMENTATION_SUMMARY.md @@ -7,6 +7,7 @@ I have successfully implemented a comprehensive offline learning mode system for ## ✅ Completed Features ### Core Functionality + - ✅ **Course Downloading**: Complete course content can be downloaded for offline viewing - ✅ **Progress Tracking**: Learning progress is tracked offline and synced when online - ✅ **Storage Management**: Comprehensive storage monitoring and management @@ -15,12 +16,14 @@ I have successfully implemented a comprehensive offline learning mode system for - ✅ **Auto-sync**: Automatic synchronization when connection is restored ### User Interface Components + - ✅ **OfflineStatusIndicator**: Shows connection status, sync state, and provides quick actions - ✅ **DownloadManager**: Intuitive interface for managing course downloads with progress tracking - ✅ **StorageManager**: Comprehensive storage management with filtering, sorting, and cleanup - ✅ **Context Provider**: Centralized state management for offline functionality ### Technical Infrastructure + - ✅ **IndexedDB Integration**: Robust database schema for offline data storage - ✅ **Sync Service**: Advanced sync service with conflict resolution and retry logic - ✅ **Performance Optimization**: Efficient data handling and storage management @@ -29,6 +32,7 @@ I have successfully implemented a comprehensive offline learning mode system for ## 🏗️ Architecture ### Component Structure + ``` src/app/ ├── context/ @@ -44,6 +48,7 @@ src/app/ ``` ### Database Schema + - **Courses Store**: Stores downloaded course content and metadata - **Progress Store**: Tracks learning progress with sync status - **Sync Queue Store**: Manages pending sync operations @@ -52,6 +57,7 @@ src/app/ ## 🧪 Testing ### Test Coverage + - ✅ **18 comprehensive tests** covering all major functionality - ✅ **Database operations**: Initialization, CRUD operations, error handling - ✅ **Course management**: Download, availability checking, progress tracking @@ -61,6 +67,7 @@ src/app/ - ✅ **Error handling**: Database errors, network failures, edge cases ### Test Results + ``` ✓ src/app/hooks/__tests__/useDashboardWidgets.test.tsx (2) ✓ src/app/hooks/__tests__/useOfflineMode.test.tsx (16) @@ -72,30 +79,35 @@ Tests 18 passed (18) ## 🚀 Key Features Implemented ### 1. Offline Mode Context + - **State Management**: Centralized offline state with React Context - **Connection Monitoring**: Real-time online/offline status detection - **Auto-sync**: Automatic synchronization when connection is restored - **Storage Monitoring**: Real-time storage usage tracking ### 2. Download Manager + - **Visual Progress**: Real-time download progress with status indicators - **Queue Management**: Multiple download support with pause/resume - **Storage Integration**: Automatic storage usage monitoring - **User Controls**: Pause, resume, cancel, and clear operations ### 3. Storage Manager + - **Comprehensive View**: List and grid views of stored content - **Advanced Filtering**: Filter by type, sort by various criteria - **Bulk Operations**: Select multiple items for deletion - **Storage Warnings**: Visual alerts for storage limits ### 4. Offline Status Indicator + - **Real-time Status**: Connection and sync status display - **Quick Actions**: Enable/disable offline mode, manual sync - **Detailed Information**: Storage usage, last sync time, pending items - **Settings Panel**: Advanced configuration options ### 5. Sync Service + - **Conflict Resolution**: Three strategies (local wins, remote wins, merge) - **Retry Logic**: Exponential backoff for failed operations - **Batch Processing**: Efficient grouping of sync operations @@ -104,18 +116,21 @@ Tests 18 passed (18) ## 🔧 Technical Achievements ### Performance Optimizations + - **Lazy Loading**: Content loaded on-demand - **Efficient Indexing**: Database indexes for fast queries - **Batch Operations**: Grouped operations for efficiency - **Memory Management**: Proper cleanup and garbage collection ### Error Handling + - **Graceful Degradation**: System continues working offline - **Automatic Recovery**: Retry mechanisms for failed operations - **User Feedback**: Clear error messages and status indicators - **Data Integrity**: Conflict resolution prevents data loss ### Browser Compatibility + - **Modern APIs**: IndexedDB, Service Workers, Storage API - **Progressive Enhancement**: Works without offline features - **Cross-browser Support**: Chrome, Firefox, Safari, Edge @@ -123,12 +138,14 @@ Tests 18 passed (18) ## 📱 User Experience ### Seamless Integration + - **Non-intrusive**: Offline components don't interfere with main UI - **Intuitive Controls**: Easy-to-understand status indicators - **Progressive Disclosure**: Detailed information available on demand - **Responsive Design**: Works on all screen sizes ### Visual Feedback + - **Status Icons**: Clear visual indicators for different states - **Progress Bars**: Real-time progress for downloads and sync - **Color Coding**: Consistent color scheme for different states @@ -137,6 +154,7 @@ Tests 18 passed (18) ## 🔒 Security & Privacy ### Data Protection + - **Local Storage**: All data stored locally in IndexedDB - **No Sensitive Data**: No passwords or sensitive information stored offline - **User Control**: Users can disable offline mode at any time @@ -145,12 +163,14 @@ Tests 18 passed (18) ## 📊 Performance Metrics ### Storage Efficiency + - **Compression**: Assets compressed before storage - **Cleanup Routines**: Automatic removal of old data - **Quota Management**: Respects browser storage limits - **Usage Monitoring**: Real-time storage usage tracking ### Network Optimization + - **Incremental Sync**: Only sync changed data - **Batch Processing**: Efficient grouping of operations - **Retry Logic**: Smart retry with exponential backoff @@ -159,26 +179,31 @@ Tests 18 passed (18) ## 🎯 Acceptance Criteria Met ✅ **Courses can be downloaded for offline viewing** + - Complete course content download functionality - Progress tracking during downloads - Storage management for downloaded content ✅ **Progress made offline is tracked and synced when online** + - Comprehensive progress tracking system - Automatic sync when connection is restored - Conflict resolution for conflicting data ✅ **Storage usage is displayed and can be managed by users** + - Real-time storage usage monitoring - Comprehensive storage management interface - Bulk operations for content management ✅ **Clear offline status indicators show when content is available offline** + - Visual status indicators throughout the UI - Real-time connection and sync status - Detailed information panels ✅ **Sync conflicts are resolved intelligently** + - Multiple conflict resolution strategies - Automatic and manual resolution options - Data integrity preservation @@ -186,6 +211,7 @@ Tests 18 passed (18) ## 🚀 Future Enhancements ### Planned Features + - **Offline Video Streaming**: Optimized video playback offline - **Advanced Compression**: Better compression algorithms - **Multi-device Sync**: Sync across multiple devices @@ -193,6 +219,7 @@ Tests 18 passed (18) - **Smart Preloading**: Predictive course downloading ### Performance Improvements + - **WebAssembly**: Use WASM for heavy computations - **Web Workers**: Background processing for sync operations - **Streaming**: Stream large files during download @@ -201,6 +228,7 @@ Tests 18 passed (18) ## 📝 Documentation ### Complete Documentation + - ✅ **API Reference**: Comprehensive documentation of all methods and properties - ✅ **Usage Examples**: Code examples for common use cases - ✅ **Architecture Guide**: Detailed technical architecture documentation diff --git a/OFFLINE_MODE_README.md b/OFFLINE_MODE_README.md index d2d881e1..abde5eb1 100644 --- a/OFFLINE_MODE_README.md +++ b/OFFLINE_MODE_README.md @@ -7,6 +7,7 @@ This implementation provides a comprehensive offline learning system for the Tea ## Features ### 🎯 Core Functionality + - **Course Downloading**: Download complete courses for offline viewing - **Progress Tracking**: Track learning progress offline with automatic sync - **Storage Management**: Monitor and manage offline storage usage @@ -14,6 +15,7 @@ This implementation provides a comprehensive offline learning system for the Tea - **Real-time Status**: Visual indicators for connection and sync status ### 📱 User Experience + - **Seamless Offline/Online Transition**: Automatic detection and handling - **Visual Status Indicators**: Clear feedback on connection and sync status - **Download Manager**: Intuitive interface for managing course downloads @@ -43,6 +45,7 @@ src/app/ The implementation uses IndexedDB with the following stores: #### Courses Store + ```typescript interface CourseData { id: string; @@ -57,6 +60,7 @@ interface CourseData { ``` #### Progress Store + ```typescript interface ProgressData { courseId: string; @@ -70,6 +74,7 @@ interface ProgressData { ``` #### Sync Queue Store + ```typescript interface SyncQueueItem { id: string; @@ -85,12 +90,14 @@ interface SyncQueueItem { ### Basic Setup 1. **Enable Offline Mode**: + ```typescript const { enableOfflineMode } = useOfflineModeContext(); await enableOfflineMode(); ``` 2. **Download a Course**: + ```typescript const { downloadCourse } = useOfflineModeContext(); await downloadCourse(courseId, courseData); @@ -105,27 +112,27 @@ interface SyncQueueItem { ### Component Integration #### Offline Status Indicator + ```tsx import { OfflineStatusIndicator } from './components/offline/OfflineStatusIndicator'; - +; ``` #### Download Manager + ```tsx import { DownloadManager } from './components/offline/DownloadManager'; - +; ``` #### Storage Manager + ```tsx import { StorageManager } from './components/offline/StorageManager'; - +; ``` ## API Reference @@ -133,6 +140,7 @@ import { StorageManager } from './components/offline/StorageManager'; ### OfflineModeContext #### State Properties + - `isOnline: boolean` - Current connection status - `isOfflineModeEnabled: boolean` - Whether offline mode is active - `syncStatus: 'idle' | 'syncing' | 'synced' | 'error'` - Current sync status @@ -141,6 +149,7 @@ import { StorageManager } from './components/offline/StorageManager'; - `storageUsage: { used: number; total: number; percentage: number }` - Storage information #### Methods + - `enableOfflineMode(): Promise` - Enable offline functionality - `disableOfflineMode(): Promise` - Disable offline functionality - `syncOfflineData(): Promise` - Manually trigger sync @@ -151,6 +160,7 @@ import { StorageManager } from './components/offline/StorageManager'; ### useOfflineMode Hook #### Methods + - `initializeOfflineMode(): Promise` - Initialize the offline database - `downloadCourse(courseId: string, courseData: any): Promise` - Download course content - `saveProgress(courseId: string, moduleId: string, progress: number, completed: boolean): Promise` - Save progress @@ -210,6 +220,7 @@ src/app/hooks/__tests__/ ``` Tests are organized into logical groups: + - Initialization tests - Course operation tests - Progress tracking tests @@ -243,12 +254,14 @@ Tests are organized into logical groups: ## Browser Compatibility ### Supported Browsers + - Chrome 60+ - Firefox 55+ - Safari 11+ - Edge 79+ ### Required APIs + - IndexedDB - Service Workers (for PWA features) - Fetch API @@ -257,12 +270,14 @@ Tests are organized into logical groups: ## Security Considerations ### Data Protection + - **Local Storage**: All data is stored locally in IndexedDB - **No Sensitive Data**: No passwords or sensitive information stored offline - **Encryption**: Consider encrypting sensitive course content - **Access Control**: Proper access controls for offline data ### Privacy + - **User Consent**: Clear consent for offline storage - **Data Retention**: Automatic cleanup of old data - **Opt-out**: Users can disable offline mode at any time @@ -270,6 +285,7 @@ Tests are organized into logical groups: ## Future Enhancements ### Planned Features + - **Offline Video Streaming**: Optimized video playback offline - **Advanced Compression**: Better compression algorithms - **Multi-device Sync**: Sync across multiple devices @@ -277,6 +293,7 @@ Tests are organized into logical groups: - **Smart Preloading**: Predictive course downloading ### Performance Improvements + - **WebAssembly**: Use WASM for heavy computations - **Web Workers**: Background processing for sync operations - **Streaming**: Stream large files during download @@ -287,16 +304,19 @@ Tests are organized into logical groups: ### Common Issues 1. **Database Initialization Failed** + - Check browser IndexedDB support - Clear browser data and retry - Check for storage quota issues 2. **Sync Conflicts** + - Review conflict resolution settings - Manually resolve conflicts if needed - Check network connectivity 3. **Storage Full** + - Use Storage Manager to clear old data - Remove unused courses - Check browser storage limits @@ -309,6 +329,7 @@ Tests are organized into logical groups: ### Debug Mode Enable debug logging by setting: + ```typescript localStorage.setItem('offline-debug', 'true'); ``` @@ -318,11 +339,13 @@ localStorage.setItem('offline-debug', 'true'); ### Development Setup 1. Install dependencies: + ```bash npm install ``` 2. Start development server: + ```bash npm run dev ``` diff --git a/README.md b/README.md index 3dcd29dd..cd9ade7f 100644 --- a/README.md +++ b/README.md @@ -147,3 +147,4 @@ let make our code clean, maintainable and scallable. Keep to Standard 📜 License MIT © 2025 TeachLink DAO +``` diff --git a/lint-staged.config.js b/lint-staged.config.js index 42f0ada1..8d610e47 100644 --- a/lint-staged.config.js +++ b/lint-staged.config.js @@ -3,7 +3,7 @@ module.exports = { // run eslint --fix on changed files `eslint --max-warnings=0 --fix ${filenames.join(' ')}`, // then format with prettier - `prettier --write ${filenames.join(' ')}` + `prettier --write ${filenames.join(' ')}`, ], - '*.{json,md,css,scss,html}': [`prettier --write ${filenames.join(' ')}`] + '*.{json,md,css,scss,html}': [`prettier --write ${filenames.join(' ')}`], }; diff --git a/next.config.ts b/next.config.ts index a4411e4a..ff23479c 100644 --- a/next.config.ts +++ b/next.config.ts @@ -1,5 +1,5 @@ -import type { NextConfig } from "next"; -import path from "path"; +import type { NextConfig } from 'next'; +import path from 'path'; const nextConfig: NextConfig = { /* config options here */ diff --git a/postcss.config.js b/postcss.config.js index 52b9b4ba..e5640725 100644 --- a/postcss.config.js +++ b/postcss.config.js @@ -2,4 +2,4 @@ module.exports = { plugins: { '@tailwindcss/postcss': {}, }, -} +}; diff --git a/postcss.config.ts b/postcss.config.ts index 1b7b8945..e5640725 100644 --- a/postcss.config.ts +++ b/postcss.config.ts @@ -2,4 +2,4 @@ module.exports = { plugins: { '@tailwindcss/postcss': {}, }, -} \ No newline at end of file +}; diff --git a/src/public/manifest.json b/public/manifest.json similarity index 100% rename from src/public/manifest.json rename to public/manifest.json diff --git a/scripts/validate-ui.js b/scripts/validate-ui.js index 71d90384..570a7fa5 100644 --- a/scripts/validate-ui.js +++ b/scripts/validate-ui.js @@ -31,22 +31,22 @@ let warnings = []; function getAllFiles(dir, extensions = ['.tsx', '.jsx', '.ts', '.js']) { let files = []; - + if (!fs.existsSync(dir)) return files; - + const items = fs.readdirSync(dir); - + for (const item of items) { const fullPath = path.join(dir, item); const stat = fs.statSync(fullPath); - + if (stat.isDirectory() && !item.startsWith('.') && item !== 'node_modules') { files = files.concat(getAllFiles(fullPath, extensions)); - } else if (stat.isFile() && extensions.some(ext => item.endsWith(ext))) { + } else if (stat.isFile() && extensions.some((ext) => item.endsWith(ext))) { files.push(fullPath); } } - + return files; } @@ -56,7 +56,7 @@ function checkIconUsage(content, filePath) { errors.push(`[ICON] ${filePath}: Uses ${name} - should use lucide-react`); } } - + // Check for react-icons usage (warning, not error) if (/from ['"]react-icons/g.test(content)) { warnings.push(`[ICON] ${filePath}: Uses react-icons - prefer lucide-react for consistency`); @@ -66,16 +66,18 @@ function checkIconUsage(content, filePath) { function checkResponsiveTailwind(content, filePath) { // Only check component files that have className if (!content.includes('className')) return; - + // Check for common layout patterns without responsive variants const lines = content.split('\n'); - + lines.forEach((line, index) => { // Check for grid/flex without any responsive classes if (/className=["'][^"']*\b(grid|flex)\b[^"']*["']/.test(line)) { const hasResponsive = /\b(sm|md|lg|xl|2xl):/.test(line); if (!hasResponsive && line.includes('grid-cols-') && !line.includes('grid-cols-1')) { - warnings.push(`[RESPONSIVE] ${filePath}:${index + 1}: Grid layout may need responsive classes`); + warnings.push( + `[RESPONSIVE] ${filePath}:${index + 1}: Grid layout may need responsive classes`, + ); } } }); @@ -91,15 +93,15 @@ function checkForConsoleStatements(content, filePath) { function validateFiles() { console.log('🔍 Running UI validation checks...\n'); - + for (const dir of COMPONENT_DIRS) { const fullDir = path.join(SRC_DIR, dir); const files = getAllFiles(fullDir); - + for (const file of files) { const content = fs.readFileSync(file, 'utf-8'); const relativePath = path.relative(process.cwd(), file); - + checkIconUsage(content, relativePath); checkResponsiveTailwind(content, relativePath); checkForConsoleStatements(content, relativePath); @@ -110,18 +112,18 @@ function validateFiles() { function printResults() { if (warnings.length > 0) { console.log('⚠️ Warnings:\n'); - warnings.forEach(w => console.log(` ${w}`)); + warnings.forEach((w) => console.log(` ${w}`)); console.log(''); } - + if (errors.length > 0) { console.log('❌ Errors:\n'); - errors.forEach(e => console.log(` ${e}`)); + errors.forEach((e) => console.log(` ${e}`)); console.log(''); console.log(`\n❌ UI validation failed with ${errors.length} error(s)`); process.exit(1); } - + console.log(`✅ UI validation passed (${warnings.length} warning(s))`); process.exit(0); } diff --git a/scripts/validate-web3.js b/scripts/validate-web3.js index 9e71b404..f7224bbd 100644 --- a/scripts/validate-web3.js +++ b/scripts/validate-web3.js @@ -16,60 +16,60 @@ let warnings = []; function checkWalletProviderExists() { const providerPath = path.join(SRC_DIR, 'providers/WalletProvider.tsx'); - + if (!fs.existsSync(providerPath)) { errors.push('[WEB3] WalletProvider.tsx not found in src/providers/'); return false; } - + const content = fs.readFileSync(providerPath, 'utf-8'); - + // Check for error handling if (!content.includes('try') || !content.includes('catch')) { errors.push('[WEB3] WalletProvider should have try-catch error handling'); } - + // Check for SSR safety - if (!content.includes("typeof window")) { + if (!content.includes('typeof window')) { warnings.push('[WEB3] WalletProvider should check for SSR (typeof window)'); } - + // Check for graceful fallback if (!content.includes('useContext') || !content.includes('null')) { warnings.push('[WEB3] useWallet hook should handle missing provider gracefully'); } - + return true; } function checkWeb3Utils() { const utilsPath = path.join(SRC_DIR, 'utils/web3/index.ts'); - + if (!fs.existsSync(utilsPath)) { errors.push('[WEB3] utils/web3/index.ts not found'); return false; } - + const envValidationPath = path.join(SRC_DIR, 'utils/web3/envValidation.ts'); if (!fs.existsSync(envValidationPath)) { errors.push('[WEB3] utils/web3/envValidation.ts not found'); return false; } - + const content = fs.readFileSync(envValidationPath, 'utf-8'); - + // Check for network validation if (!content.includes('NEXT_PUBLIC_STARKNET')) { warnings.push('[WEB3] Environment validation should check NEXT_PUBLIC_STARKNET_* vars'); } - + return true; } function checkEnvExample() { const envExamplePath = path.join(__dirname, '../.env.example'); const envLocalPath = path.join(__dirname, '../.env.local.example'); - + if (!fs.existsSync(envExamplePath) && !fs.existsSync(envLocalPath)) { warnings.push('[WEB3] Consider adding .env.example with NEXT_PUBLIC_STARKNET_* variables'); } @@ -77,25 +77,25 @@ function checkEnvExample() { function printResults() { console.log('🔍 Running Web3 validation checks...\n'); - + checkWalletProviderExists(); checkWeb3Utils(); checkEnvExample(); - + if (warnings.length > 0) { console.log('⚠️ Warnings:\n'); - warnings.forEach(w => console.log(` ${w}`)); + warnings.forEach((w) => console.log(` ${w}`)); console.log(''); } - + if (errors.length > 0) { console.log('❌ Errors:\n'); - errors.forEach(e => console.log(` ${e}`)); + errors.forEach((e) => console.log(` ${e}`)); console.log(''); console.log(`\n❌ Web3 validation failed with ${errors.length} error(s)`); process.exit(1); } - + console.log(`✅ Web3 validation passed (${warnings.length} warning(s))`); process.exit(0); } diff --git a/src/app/components/accessibility/README.md b/src/app/components/accessibility/README.md index a150b09d..6612133a 100644 --- a/src/app/components/accessibility/README.md +++ b/src/app/components/accessibility/README.md @@ -5,31 +5,36 @@ This directory contains comprehensive accessibility features ensuring WCAG 2.1 A ## Components ### 1. AccessibilityNavigator + Provides keyboard navigation and skip links for efficient page navigation. **Features:** + - Skip to main content, navigation, and footer - Landmark navigation menu - Keyboard shortcuts reference - Visual navigation helper **Usage:** + ```tsx import { AccessibilityNavigator } from '@/app/components/accessibility/AccessibilityNavigator'; - +/>; ``` ### 2. ScreenReaderOptimizer + Optimizes content for screen readers with ARIA labels and live regions. **Features:** + - Automatic screen reader detection - ARIA live regions for announcements - Accessible loading states @@ -37,12 +42,13 @@ Optimizes content for screen readers with ARIA labels and live regions. - Progress indicators with proper ARIA attributes **Usage:** + ```tsx -import { +import { ScreenReaderOptimizer, AccessibleLoading, AccessibleError, - AccessibleProgress + AccessibleProgress } from '@/app/components/accessibility/ScreenReaderOptimizer'; @@ -60,9 +66,11 @@ import { ``` ### 3. ColorContrastChecker + Validates color contrast ratios against WCAG standards. **Features:** + - Automatic page contrast checking - Visual contrast ratio display - WCAG AA/AAA compliance indicators @@ -70,19 +78,19 @@ Validates color contrast ratios against WCAG standards. - Detailed failure reports **Usage:** + ```tsx import { ColorContrastChecker } from '@/app/components/accessibility/ColorContrastChecker'; - +; ``` ### 4. AccessibilityTester + Automated accessibility testing and issue reporting. **Features:** + - Comprehensive accessibility checks - Issue severity classification (critical, serious, moderate, minor) - WCAG criteria mapping @@ -90,19 +98,19 @@ Automated accessibility testing and issue reporting. - Real-time issue filtering **Usage:** + ```tsx import { AccessibilityTester } from '@/app/components/accessibility/AccessibilityTester'; - +; ``` ### 5. AccessibilityProvider + Wrapper component that enables all accessibility features. **Usage:** + ```tsx import { AccessibilityProvider } from '@/app/components/accessibility/AccessibilityProvider'; @@ -125,6 +133,7 @@ function App() { ## Hooks ### useKeyboardNavigation + Manages keyboard navigation within a container. ```tsx @@ -135,6 +144,7 @@ return
{/* content */}
; ``` ### useFocusTrap + Traps focus within a container (for modals/dialogs). ```tsx @@ -145,6 +155,7 @@ return
{/* modal content */}
; ``` ### useScreenReaderAnnouncement + Announces messages to screen readers. ```tsx @@ -155,6 +166,7 @@ announce('Form submitted successfully', 'polite'); ``` ### useAccessibilityCheck + Performs accessibility checks on a container. ```tsx @@ -164,6 +176,7 @@ const { containerRef, issues, checkAccessibility } = useAccessibilityCheck(false ``` ### useReducedMotion + Detects user's reduced motion preference. ```tsx @@ -176,6 +189,7 @@ const animationDuration = prefersReducedMotion ? 0 : 300; ## Utility Functions ### calculateContrastRatio + Calculates contrast ratio between two colors. ```tsx @@ -187,18 +201,20 @@ console.log(result.passes.aa); // true ``` ### checkAccessibilityIssues + Checks for common accessibility issues in a container. ```tsx import { checkAccessibilityIssues } from '@/utils/accessibilityUtils'; const issues = checkAccessibilityIssues(document.body); -issues.forEach(issue => { +issues.forEach((issue) => { console.log(issue.severity, issue.message); }); ``` ### announceToScreenReader + Announces a message to screen readers. ```tsx @@ -210,12 +226,14 @@ announceToScreenReader('Page loaded', 'polite'); ## WCAG 2.1 AA Compliance Checklist ### ✅ Perceivable + - [x] 1.1.1 Non-text Content - Alt text checking - [x] 1.3.1 Info and Relationships - Semantic HTML and ARIA - [x] 1.4.3 Contrast (Minimum) - Color contrast checker - [x] 1.4.11 Non-text Contrast - UI component contrast ### ✅ Operable + - [x] 2.1.1 Keyboard - Full keyboard navigation - [x] 2.1.2 No Keyboard Trap - Focus trap management - [x] 2.4.1 Bypass Blocks - Skip links @@ -223,27 +241,31 @@ announceToScreenReader('Page loaded', 'polite'); - [x] 2.4.7 Focus Visible - Visible focus indicators ### ✅ Understandable + - [x] 3.1.1 Language of Page - Lang attributes - [x] 3.2.1 On Focus - No unexpected changes - [x] 3.3.1 Error Identification - Accessible errors - [x] 3.3.2 Labels or Instructions - Form labels ### ✅ Robust + - [x] 4.1.2 Name, Role, Value - ARIA attributes - [x] 4.1.3 Status Messages - Live regions ## Testing ### Manual Testing + 1. **Keyboard Navigation**: Navigate entire site using only Tab, Shift+Tab, Enter, and Arrow keys 2. **Screen Reader**: Test with NVDA (Windows), JAWS (Windows), or VoiceOver (Mac) 3. **Zoom**: Test at 200% zoom level 4. **Color Blindness**: Use browser extensions to simulate color blindness ### Automated Testing + ```tsx // Run accessibility check - +; // Or programmatically const { issues, checkAccessibility } = useAccessibilityCheck(); diff --git a/src/app/globals.css b/src/app/globals.css index bd314677..8ddaf89d 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -1,8 +1,8 @@ -@import "tailwindcss"; +@import 'tailwindcss'; :root { --background: #ffffff; - --foreground: #0F172A; + --foreground: #0f172a; } @media (prefers-color-scheme: dark) { @@ -10,7 +10,7 @@ /* Keeping light mode defaults as per provided design for now, but setup for dark mode override if needed later */ --background: #ffffff; - --foreground: #0F172A; + --foreground: #0f172a; } } @@ -74,36 +74,36 @@ a[data-skip-link]:focus { } /* RTL Support */ - [dir="rtl"] { + [dir='rtl'] { direction: rtl; } - [dir="ltr"] { + [dir='ltr'] { direction: ltr; } /* RTL-aware spacing utilities */ - [dir="rtl"] .ml-auto { + [dir='rtl'] .ml-auto { margin-left: 0; margin-right: auto; } - [dir="rtl"] .mr-auto { + [dir='rtl'] .mr-auto { margin-right: 0; margin-left: auto; } /* RTL-aware text alignment */ - [dir="rtl"] .text-left { + [dir='rtl'] .text-left { text-align: right; } - [dir="rtl"] .text-right { + [dir='rtl'] .text-right { text-align: left; } /* Updated Range Input Styling specific to design */ - input[type=range] { + input[type='range'] { -webkit-appearance: none; appearance: none; height: 2px; @@ -112,7 +112,7 @@ a[data-skip-link]:focus { outline: none; } - input[type=range]::-webkit-slider-thumb { + input[type='range']::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; height: 16px; @@ -127,7 +127,7 @@ a[data-skip-link]:focus { } /* Firefox */ - input[type=range]::-moz-range-thumb { + input[type='range']::-moz-range-thumb { height: 16px; width: 16px; border-radius: 50%; @@ -137,7 +137,7 @@ a[data-skip-link]:focus { box-shadow: 0 0 0 2px rgba(0, 102, 255, 0.1); } - input[type=range]::-webkit-slider-runnable-track { + input[type='range']::-webkit-slider-runnable-track { width: 100%; height: 4px; cursor: pointer; @@ -145,7 +145,7 @@ a[data-skip-link]:focus { border-radius: 0; } - input[type=range]::-moz-range-track { + input[type='range']::-moz-range-track { width: 100%; height: 4px; cursor: pointer; diff --git a/src/components/pwa/AppUpdateManager.tsx b/src/components/pwa/AppUpdateManager.tsx index 2f8e9d11..2b7dff87 100644 --- a/src/components/pwa/AppUpdateManager.tsx +++ b/src/components/pwa/AppUpdateManager.tsx @@ -36,7 +36,7 @@ export const AppUpdateManager: React.FC = () => {
-