diff --git a/.vercelignore b/.vercelignore new file mode 100644 index 0000000..b60317b --- /dev/null +++ b/.vercelignore @@ -0,0 +1,11 @@ +node_modules +.env.local +.env.development.local +.env.test.local +.env.production.local +.git +*.log +.DS_Store +dev-dist +android +ios diff --git a/src/App.tsx b/src/App.tsx index 88e1d1d..27dd300 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,6 +1,7 @@ import { IonApp, IonRouterOutlet, setupIonicReact } from "@ionic/react"; import { IonReactRouter } from "@ionic/react-router"; import { Route, Redirect } from "react-router-dom"; +import { useState, useEffect } from "react"; import Home from "./pages/Home"; import FilesPage from "./pages/FilesPage"; import SettingsPage from "./pages/SettingsPage"; @@ -36,7 +37,26 @@ setupIonicReact(); const AppContent: React.FC = () => { const { isDarkMode } = useTheme(); const { isOnline } = usePWA(); - const showLandingPage = isNewUser(); + const [showLandingPage, setShowLandingPage] = useState(isNewUser()); + + // Listen for storage changes to update landing page visibility + useEffect(() => { + const handleStorageChange = () => { + setShowLandingPage(isNewUser()); + }; + + window.addEventListener("storage", handleStorageChange); + + // Also check periodically for changes made in the same tab + const interval = setInterval(() => { + setShowLandingPage(isNewUser()); + }, 100); + + return () => { + window.removeEventListener("storage", handleStorageChange); + clearInterval(interval); + }; + }, []); return ( diff --git a/src/pages/FilesPage.tsx b/src/pages/FilesPage.tsx index 97506d3..4b6c4c5 100644 --- a/src/pages/FilesPage.tsx +++ b/src/pages/FilesPage.tsx @@ -940,7 +940,9 @@ const FilesPage: React.FC = () => { return (
handleTemplateSelect(template.templateId)} + onClick={() => + handleTemplateSelect(template.templateId) + } style={{ border: "2px solid var(--ion-color-light)", borderRadius: "12px", diff --git a/src/pages/LandingPage.tsx b/src/pages/LandingPage.tsx index 4d0e48c..f28daa2 100644 --- a/src/pages/LandingPage.tsx +++ b/src/pages/LandingPage.tsx @@ -40,15 +40,23 @@ const LandingPage: React.FC = () => { // Check authentication status on component mount useEffect(() => { // if (cloudService.isAuthenticated()) { - // history.push("/app/editor"); + // history.push("/app/files"); // } }, [history]); const handleGetStarted = () => { - // Mark user as existing (no longer new) - markUserAsExisting(); - // Navigate to the editor - history.push("/app/editor"); + console.log("handleGetStarted called"); + try { + // Mark user as existing (no longer new) + markUserAsExisting(); + console.log("User marked as existing"); + // Navigate to the files page - use replace to avoid back button issues + console.log("Navigating to /app/files"); + history.replace("/app/files"); + console.log("Navigation completed"); + } catch (error) { + console.error("Error in handleGetStarted:", error); + } }; const features = [ @@ -241,7 +249,7 @@ const LandingPage: React.FC = () => { className="cta-button" onClick={handleGetStarted} > - Access Invoice Editor + Access File Manager
diff --git a/vercel.json b/vercel.json index 851a7ee..ab614c1 100644 --- a/vercel.json +++ b/vercel.json @@ -1,4 +1,10 @@ { + "rewrites": [ + { + "source": "/(.*)", + "destination": "/index.html" + } + ], "headers": [ { "source": "/sw.js", @@ -9,6 +15,15 @@ } ] }, + { + "source": "/workbox-(.*).js", + "headers": [ + { + "key": "Cache-Control", + "value": "no-cache, no-store, must-revalidate" + } + ] + }, { "source": "/manifest.json", "headers": [ @@ -17,6 +32,15 @@ "value": "public, max-age=31536000, immutable" } ] + }, + { + "source": "/assets/(.*)", + "headers": [ + { + "key": "Cache-Control", + "value": "public, max-age=31536000, immutable" + } + ] } ] } diff --git a/vite.config.ts b/vite.config.ts index eb94675..87c4b51 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -4,18 +4,21 @@ import { VitePWA } from "vite-plugin-pwa"; // https://vitejs.dev/config/ export default defineConfig({ + base: "/", plugins: [ - react(), - VitePWA({ + react(), + VitePWA({ registerType: "autoUpdate", workbox: { - globPatterns: ['**/*.{js,css,html,ico,png,svg,json,txt,woff2}'], + globPatterns: ["**/*.{js,css,html,ico,png,svg,json,txt,woff2}"], + navigateFallback: "index.html", + navigateFallbackDenylist: [/^\/_/, /\/[^/?]+\.[^/]+$/], runtimeCaching: [ { urlPattern: /^https:\/\/api\./, - handler: 'NetworkFirst', + handler: "NetworkFirst", options: { - cacheName: 'api-cache', + cacheName: "api-cache", expiration: { maxEntries: 50, maxAgeSeconds: 5 * 60, // 5 minutes @@ -24,9 +27,9 @@ export default defineConfig({ }, { urlPattern: /.*\.(?:png|jpg|jpeg|svg|gif|webp)/, - handler: 'CacheFirst', + handler: "CacheFirst", options: { - cacheName: 'images-cache', + cacheName: "images-cache", expiration: { maxEntries: 100, maxAgeSeconds: 30 * 24 * 60 * 60, // 30 days @@ -35,52 +38,53 @@ export default defineConfig({ }, ], skipWaiting: true, - clientsClaim: true + clientsClaim: true, }, manifest: { - name: 'Govt Invoice Billing App', - short_name: 'Invoice App', - description: 'Government Invoice Billing Application - Create, manage and track invoices offline and online', - theme_color: '#3880ff', - background_color: '#ffffff', - display: 'standalone', - orientation: 'portrait-primary', - scope: '/', - start_url: '/', + name: "Govt Invoice Billing App", + short_name: "Invoice App", + description: + "Government Invoice Billing Application - Create, manage and track invoices offline and online", + theme_color: "#3880ff", + background_color: "#ffffff", + display: "standalone", + orientation: "portrait-primary", + scope: "/", + start_url: "/", icons: [ { - src: 'pwa-192x192.png', - sizes: '192x192', - type: 'image/png', - purpose: 'any' + src: "pwa-192x192.png", + sizes: "192x192", + type: "image/png", + purpose: "any", }, { - src: 'pwa-512x512.png', - sizes: '512x512', - type: 'image/png', - purpose: 'any' + src: "pwa-512x512.png", + sizes: "512x512", + type: "image/png", + purpose: "any", }, { - src: 'maskable-icon-512x512.png', - sizes: '512x512', - type: 'image/png', - purpose: 'maskable' - } - ] + src: "maskable-icon-512x512.png", + sizes: "512x512", + type: "image/png", + purpose: "maskable", + }, + ], }, devOptions: { - enabled: false // Disable in dev to avoid conflicts - } - }) + enabled: false, // Disable in dev to avoid conflicts + }, + }), ], define: { __DATE__: `'${new Date().toISOString()}'`, - global: 'globalThis', + global: "globalThis", }, build: { target: "es2020", minify: "esbuild", - sourcemap: false + sourcemap: false, }, esbuild: { target: "es2020",