diff --git a/pcomparator/.yarn/cache/@dotmind-react-use-pwa-npm-1.0.4-303d6d74b3-e040cd4ed3.zip b/pcomparator/.yarn/cache/@dotmind-react-use-pwa-npm-1.0.4-303d6d74b3-e040cd4ed3.zip new file mode 100644 index 0000000..9f04aea Binary files /dev/null and b/pcomparator/.yarn/cache/@dotmind-react-use-pwa-npm-1.0.4-303d6d74b3-e040cd4ed3.zip differ diff --git a/pcomparator/.yarn/cache/moment-npm-2.30.1-1c51a5c631-859236bab1.zip b/pcomparator/.yarn/cache/moment-npm-2.30.1-1c51a5c631-859236bab1.zip new file mode 100644 index 0000000..7454cc2 Binary files /dev/null and b/pcomparator/.yarn/cache/moment-npm-2.30.1-1c51a5c631-859236bab1.zip differ diff --git a/pcomparator/next.config.ts b/pcomparator/next.config.ts index a3ab3df..2336fdb 100644 --- a/pcomparator/next.config.ts +++ b/pcomparator/next.config.ts @@ -54,6 +54,7 @@ const nextConfig = (): NextConfig => { const withPWA = withPWAInit({ dest: "public", + disable: false }); -module.exports = nextConfig(); +module.exports = withPWA(nextConfig()); diff --git a/pcomparator/package.json b/pcomparator/package.json index 3601a5d..bb78e8d 100644 --- a/pcomparator/package.json +++ b/pcomparator/package.json @@ -1,6 +1,6 @@ { "name": "pcomparator", - "version": "1.0.0", + "version": "4.8.0", "private": true, "scripts": { "dev": "next dev --turbo", @@ -23,6 +23,7 @@ "dependencies": { "@asteasolutions/zod-to-openapi": "^7.2.0", "@auth/prisma-adapter": "^2.7.2", + "@dotmind/react-use-pwa": "^1.0.4", "@imbios/next-pwa": "^1.1.1", "@lingui/core": "^4.11.0", "@lingui/react": "^4.11.0", @@ -49,6 +50,7 @@ "kysely": "^0.27.4", "lodash": "^4.17.21", "lucide-react": "^0.453.0", + "moment": "^2.30.1", "next": "15.0.0", "next-auth": "beta", "next-themes": "^0.3.0", diff --git a/pcomparator/public/sw.js b/pcomparator/public/sw.js index 81442fe..027d26e 100644 --- a/pcomparator/public/sw.js +++ b/pcomparator/public/sw.js @@ -1 +1 @@ -if(!self.define){let e,s={};const i=(i,a)=>(i=new URL(i+".js",a).href,s[i]||new Promise((s=>{if("document"in self){const e=document.createElement("script");e.src=i,e.onload=s,document.head.appendChild(e)}else e=i,importScripts(i),s()})).then((()=>{let e=s[i];if(!e)throw new Error(`Module ${i} didn’t register its module`);return e})));self.define=(a,t)=>{const n=e||("document"in self?document.currentScript.src:"")||location.href;if(s[n])return;let c={};const r=e=>i(e,n),o={module:{uri:n},exports:c,require:r};s[n]=Promise.all(a.map((e=>o[e]||r(e)))).then((e=>(t(...e),c)))}}define(["./workbox-f1770938"],(function(e){"use strict";importScripts(),self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"/_next/static/TsF_TUVp5OQ3RUlViPMmF/_buildManifest.js",revision:"27cff35029d0f5090ddb6f5b508df290"},{url:"/_next/static/TsF_TUVp5OQ3RUlViPMmF/_ssgManifest.js",revision:"b6652df95db52feb4daf4eca35380933"},{url:"/_next/static/chunks/128-31dbe0f76bbbd36a.js",revision:"TsF_TUVp5OQ3RUlViPMmF"},{url:"/_next/static/chunks/151-8fda21ef84762abb.js",revision:"TsF_TUVp5OQ3RUlViPMmF"},{url:"/_next/static/chunks/263.3ca24e9aea7faea7.js",revision:"3ca24e9aea7faea7"},{url:"/_next/static/chunks/279-89c31bafd7b6bf5e.js",revision:"TsF_TUVp5OQ3RUlViPMmF"},{url:"/_next/static/chunks/290.3666e53ebc075411.js",revision:"3666e53ebc075411"},{url:"/_next/static/chunks/36-1d98fbbdfa5295bc.js",revision:"TsF_TUVp5OQ3RUlViPMmF"},{url:"/_next/static/chunks/40-f79344098f57116e.js",revision:"TsF_TUVp5OQ3RUlViPMmF"},{url:"/_next/static/chunks/414-141e816f779212a2.js",revision:"TsF_TUVp5OQ3RUlViPMmF"},{url:"/_next/static/chunks/478-6503b3bcf9d3842b.js",revision:"TsF_TUVp5OQ3RUlViPMmF"},{url:"/_next/static/chunks/492-ff4a3b66021b1de7.js",revision:"TsF_TUVp5OQ3RUlViPMmF"},{url:"/_next/static/chunks/4bd1b696-a6847c286c0f091f.js",revision:"TsF_TUVp5OQ3RUlViPMmF"},{url:"/_next/static/chunks/517-32e28d900e13470a.js",revision:"TsF_TUVp5OQ3RUlViPMmF"},{url:"/_next/static/chunks/55-2e6bbe67ef6f0992.js",revision:"TsF_TUVp5OQ3RUlViPMmF"},{url:"/_next/static/chunks/597-3d8ca415aa1fb63f.js",revision:"TsF_TUVp5OQ3RUlViPMmF"},{url:"/_next/static/chunks/607.5b737bb7f6e04aaf.js",revision:"5b737bb7f6e04aaf"},{url:"/_next/static/chunks/73-d6ff32a3d55ac442.js",revision:"TsF_TUVp5OQ3RUlViPMmF"},{url:"/_next/static/chunks/app/%5Blocale%5D/dashboard/layout-4915dc6a3d668fbe.js",revision:"TsF_TUVp5OQ3RUlViPMmF"},{url:"/_next/static/chunks/app/%5Blocale%5D/dashboard/my-prices/page-4b3fbc2592be14e0.js",revision:"TsF_TUVp5OQ3RUlViPMmF"},{url:"/_next/static/chunks/app/%5Blocale%5D/dashboard/page-07ee9b09e1c181a4.js",revision:"TsF_TUVp5OQ3RUlViPMmF"},{url:"/_next/static/chunks/app/%5Blocale%5D/layout-c4189b93f6e3afd4.js",revision:"TsF_TUVp5OQ3RUlViPMmF"},{url:"/_next/static/chunks/app/%5Blocale%5D/page-9997f81a1d0c2d9a.js",revision:"TsF_TUVp5OQ3RUlViPMmF"},{url:"/_next/static/chunks/app/%5Blocale%5D/settings/page-3c742d063c129e94.js",revision:"TsF_TUVp5OQ3RUlViPMmF"},{url:"/_next/static/chunks/app/_not-found/page-2c7b7d1cf07bd090.js",revision:"TsF_TUVp5OQ3RUlViPMmF"},{url:"/_next/static/chunks/app/api/auth/%5B...nextauth%5D/route-c41eb90ff51a6b13.js",revision:"TsF_TUVp5OQ3RUlViPMmF"},{url:"/_next/static/chunks/app/api/v1/prices/route-bd247f9a30dcd52f.js",revision:"TsF_TUVp5OQ3RUlViPMmF"},{url:"/_next/static/chunks/app/api/v1/user/%5Bid%5D/account/route-d5cf841acfafc593.js",revision:"TsF_TUVp5OQ3RUlViPMmF"},{url:"/_next/static/chunks/app/api/v1/user/%5Bid%5D/prices/%5BpriceId%5D/route-ea06ee6ee40971ca.js",revision:"TsF_TUVp5OQ3RUlViPMmF"},{url:"/_next/static/chunks/app/api/v1/user/%5Bid%5D/prices/route-f6279046312c76c0.js",revision:"TsF_TUVp5OQ3RUlViPMmF"},{url:"/_next/static/chunks/app/api/v1/user/%5Bid%5D/profile/avatar/route-f4d01b3c2be0a2e2.js",revision:"TsF_TUVp5OQ3RUlViPMmF"},{url:"/_next/static/chunks/app/api/v1/user/%5Bid%5D/profile/route-8e3331908e6f248f.js",revision:"TsF_TUVp5OQ3RUlViPMmF"},{url:"/_next/static/chunks/e37a0b60-b74be3d42787b18d.js",revision:"TsF_TUVp5OQ3RUlViPMmF"},{url:"/_next/static/chunks/framework-f66176bb897dc684.js",revision:"TsF_TUVp5OQ3RUlViPMmF"},{url:"/_next/static/chunks/main-3f6e75635224f655.js",revision:"TsF_TUVp5OQ3RUlViPMmF"},{url:"/_next/static/chunks/main-app-499b908c1e14996d.js",revision:"TsF_TUVp5OQ3RUlViPMmF"},{url:"/_next/static/chunks/pages/_app-6a626577ffa902a4.js",revision:"TsF_TUVp5OQ3RUlViPMmF"},{url:"/_next/static/chunks/pages/_error-1be831200e60c5c0.js",revision:"TsF_TUVp5OQ3RUlViPMmF"},{url:"/_next/static/chunks/polyfills-42372ed130431b0a.js",revision:"846118c33b2c0e922d7b3a7676f81f6f"},{url:"/_next/static/chunks/webpack-45c02304d64425a0.js",revision:"TsF_TUVp5OQ3RUlViPMmF"},{url:"/_next/static/css/05cc92c67fe67fb5.css",revision:"05cc92c67fe67fb5"},{url:"/_next/static/css/99fb210130ed49f3.css",revision:"99fb210130ed49f3"},{url:"/_next/static/media/26a46d62cd723877-s.woff2",revision:"befd9c0fdfa3d8a645d5f95717ed6420"},{url:"/_next/static/media/55c55f0601d81cf3-s.woff2",revision:"43828e14271c77b87e3ed582dbff9f74"},{url:"/_next/static/media/581909926a08bbc8-s.woff2",revision:"f0b86e7c24f455280b8df606b89af891"},{url:"/_next/static/media/6d93bde91c0c2823-s.woff2",revision:"621a07228c8ccbfd647918f1021b4868"},{url:"/_next/static/media/97e0cb1ae144a2a9-s.woff2",revision:"e360c61c5bd8d90639fd4503c829c2dc"},{url:"/_next/static/media/a34f9d1faa5f3315-s.p.woff2",revision:"d4fe31e6a2aebc06b8d6e558c9141119"},{url:"/_next/static/media/df0a9ae256c0569c-s.woff2",revision:"d54db44de5ccb18886ece2fda72bdfe0"},{url:"/_next/static/media/logo.af74964e.png",revision:"47b84a04dca72c139e6f1c360998ae6e"},{url:"/manifest.json",revision:"180c42e2d45dc89fa94620a7942e4823"},{url:"/openapi.yaml",revision:"202d5999ac057412dbfbe0b1a5be9f3d"},{url:"/service-worker.js",revision:"4f5b998def3df2d4a67f307e8fb251ad"},{url:"/static/algolia.png",revision:"d36577ab9bc617c8545cff97181861b7"},{url:"/static/images/templates/products/milk-template.webp",revision:"0bc05700930282f2b066755cf7bc6969"},{url:"/static/logo.png",revision:"47b84a04dca72c139e6f1c360998ae6e"}],{ignoreURLParametersMatching:[/^utm_/,/^fbclid$/]}),e.cleanupOutdatedCaches(),e.registerRoute("/",new e.NetworkFirst({cacheName:"start-url",plugins:[{cacheWillUpdate:function(e){return _ref.apply(this,arguments)}}]}),"GET"),e.registerRoute(/^https:\/\/fonts\.(?:gstatic)\.com\/.*/i,new e.CacheFirst({cacheName:"google-fonts-webfonts",plugins:[new e.ExpirationPlugin({maxEntries:4,maxAgeSeconds:31536e3})]}),"GET"),e.registerRoute(/^https:\/\/fonts\.(?:googleapis)\.com\/.*/i,new e.StaleWhileRevalidate({cacheName:"google-fonts-stylesheets",plugins:[new e.ExpirationPlugin({maxEntries:4,maxAgeSeconds:604800})]}),"GET"),e.registerRoute(/\.(?:eot|otf|ttc|ttf|woff|woff2|font.css)$/i,new e.StaleWhileRevalidate({cacheName:"static-font-assets",plugins:[new e.ExpirationPlugin({maxEntries:4,maxAgeSeconds:604800})]}),"GET"),e.registerRoute(/\.(?:jpg|jpeg|gif|png|svg|ico|webp)$/i,new e.StaleWhileRevalidate({cacheName:"static-image-assets",plugins:[new e.ExpirationPlugin({maxEntries:64,maxAgeSeconds:2592e3})]}),"GET"),e.registerRoute(/\/_next\/static.+\.js$/i,new e.CacheFirst({cacheName:"next-static-js-assets",plugins:[new e.ExpirationPlugin({maxEntries:64,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\/_next\/image\?url=.+$/i,new e.StaleWhileRevalidate({cacheName:"next-image",plugins:[new e.ExpirationPlugin({maxEntries:64,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:mp3|wav|ogg)$/i,new e.CacheFirst({cacheName:"static-audio-assets",plugins:[new e.RangeRequestsPlugin,new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:mp4|webm)$/i,new e.CacheFirst({cacheName:"static-video-assets",plugins:[new e.RangeRequestsPlugin,new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:js)$/i,new e.StaleWhileRevalidate({cacheName:"static-js-assets",plugins:[new e.ExpirationPlugin({maxEntries:48,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:css|less)$/i,new e.StaleWhileRevalidate({cacheName:"static-style-assets",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\/_next\/data\/.+\/.+\.json$/i,new e.StaleWhileRevalidate({cacheName:"next-data",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:json|xml|csv)$/i,new e.NetworkFirst({cacheName:"static-data-assets",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute((function(e){var s=e.sameOrigin,i=e.url.pathname;return!(!s||i.startsWith("/api/auth/callback")||!i.startsWith("/api/"))}),new e.NetworkFirst({cacheName:"apis",networkTimeoutSeconds:10,plugins:[new e.ExpirationPlugin({maxEntries:16,maxAgeSeconds:86400})]}),"GET"),e.registerRoute((function(e){var s=e.request,i=e.url.pathname,a=e.sameOrigin;return"1"===s.headers.get("RSC")&&"1"===s.headers.get("Next-Router-Prefetch")&&a&&!i.startsWith("/api/")}),new e.NetworkFirst({cacheName:"pages-rsc-prefetch",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute((function(e){var s=e.request,i=e.url.pathname,a=e.sameOrigin;return"1"===s.headers.get("RSC")&&a&&!i.startsWith("/api/")}),new e.NetworkFirst({cacheName:"pages-rsc",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute((function(e){var s=e.url.pathname;return e.sameOrigin&&!s.startsWith("/api/")}),new e.NetworkFirst({cacheName:"pages",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute((function(e){return!e.sameOrigin}),new e.NetworkFirst({cacheName:"cross-origin",networkTimeoutSeconds:10,plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:3600})]}),"GET")})); +if(!self.define){let e,s={};const n=(n,a)=>(n=new URL(n+".js",a).href,s[n]||new Promise((s=>{if("document"in self){const e=document.createElement("script");e.src=n,e.onload=s,document.head.appendChild(e)}else e=n,importScripts(n),s()})).then((()=>{let e=s[n];if(!e)throw new Error(`Module ${n} didn’t register its module`);return e})));self.define=(a,c)=>{const i=e||("document"in self?document.currentScript.src:"")||location.href;if(s[i])return;let t={};const r=e=>n(e,i),o={module:{uri:i},exports:t,require:r};s[i]=Promise.all(a.map((e=>o[e]||r(e)))).then((e=>(c(...e),t)))}}define(["./workbox-f1770938"],(function(e){"use strict";importScripts(),self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"/_next/static/Gn2_GgwK_xCyR1KG1wC5R/_buildManifest.js",revision:"6d6885a0b4373a172e0bef8a6a02f9ee"},{url:"/_next/static/Gn2_GgwK_xCyR1KG1wC5R/_ssgManifest.js",revision:"b6652df95db52feb4daf4eca35380933"},{url:"/_next/static/chunks/104.aa1706bcc85c7fe3.js",revision:"aa1706bcc85c7fe3"},{url:"/_next/static/chunks/116-e21cd17c36e3f49f.js",revision:"Gn2_GgwK_xCyR1KG1wC5R"},{url:"/_next/static/chunks/279-267d0da9528ff717.js",revision:"Gn2_GgwK_xCyR1KG1wC5R"},{url:"/_next/static/chunks/320-211d725a18ce8a88.js",revision:"Gn2_GgwK_xCyR1KG1wC5R"},{url:"/_next/static/chunks/40-202476cc3ad72112.js",revision:"Gn2_GgwK_xCyR1KG1wC5R"},{url:"/_next/static/chunks/421-38591887f493feae.js",revision:"Gn2_GgwK_xCyR1KG1wC5R"},{url:"/_next/static/chunks/4bd1b696-c7389da1b006e729.js",revision:"Gn2_GgwK_xCyR1KG1wC5R"},{url:"/_next/static/chunks/506-19581e054077e252.js",revision:"Gn2_GgwK_xCyR1KG1wC5R"},{url:"/_next/static/chunks/55-0bcdf10b3bedcd88.js",revision:"Gn2_GgwK_xCyR1KG1wC5R"},{url:"/_next/static/chunks/558-cfd2b65145235095.js",revision:"Gn2_GgwK_xCyR1KG1wC5R"},{url:"/_next/static/chunks/690-98c1f6460a35828b.js",revision:"Gn2_GgwK_xCyR1KG1wC5R"},{url:"/_next/static/chunks/806-760c4e08c3c6254e.js",revision:"Gn2_GgwK_xCyR1KG1wC5R"},{url:"/_next/static/chunks/896-66cfbe71e83cc245.js",revision:"Gn2_GgwK_xCyR1KG1wC5R"},{url:"/_next/static/chunks/971.2c38701ff99dc4db.js",revision:"2c38701ff99dc4db"},{url:"/_next/static/chunks/app/%5Blocale%5D/dashboard/layout-48eb9276b4fb16bf.js",revision:"Gn2_GgwK_xCyR1KG1wC5R"},{url:"/_next/static/chunks/app/%5Blocale%5D/dashboard/my-prices/page-a9ec8fce0d014901.js",revision:"Gn2_GgwK_xCyR1KG1wC5R"},{url:"/_next/static/chunks/app/%5Blocale%5D/dashboard/page-77997a763b6a8452.js",revision:"Gn2_GgwK_xCyR1KG1wC5R"},{url:"/_next/static/chunks/app/%5Blocale%5D/layout-c2ce2d2fbf440842.js",revision:"Gn2_GgwK_xCyR1KG1wC5R"},{url:"/_next/static/chunks/app/%5Blocale%5D/page-a306f5b7c4b0f567.js",revision:"Gn2_GgwK_xCyR1KG1wC5R"},{url:"/_next/static/chunks/app/%5Blocale%5D/settings/page-1915dfa48019e533.js",revision:"Gn2_GgwK_xCyR1KG1wC5R"},{url:"/_next/static/chunks/app/_not-found/page-5c5fb3c483eeade9.js",revision:"Gn2_GgwK_xCyR1KG1wC5R"},{url:"/_next/static/chunks/app/api/auth/%5B...nextauth%5D/route-c71c05c0f24b917f.js",revision:"Gn2_GgwK_xCyR1KG1wC5R"},{url:"/_next/static/chunks/app/api/v1/prices/route-b59349778c1856a0.js",revision:"Gn2_GgwK_xCyR1KG1wC5R"},{url:"/_next/static/chunks/app/api/v1/prices/search/route-a9e1b554cbb822b3.js",revision:"Gn2_GgwK_xCyR1KG1wC5R"},{url:"/_next/static/chunks/app/api/v1/products/%5Bbarcode%5D/route-fc35bacf310120e4.js",revision:"Gn2_GgwK_xCyR1KG1wC5R"},{url:"/_next/static/chunks/app/api/v1/user/%5Bid%5D/account/route-b059e4273ce0f4be.js",revision:"Gn2_GgwK_xCyR1KG1wC5R"},{url:"/_next/static/chunks/app/api/v1/user/%5Bid%5D/prices/%5BpriceId%5D/route-754e02697f2b2f99.js",revision:"Gn2_GgwK_xCyR1KG1wC5R"},{url:"/_next/static/chunks/app/api/v1/user/%5Bid%5D/prices/route-4d7b1cad70acf695.js",revision:"Gn2_GgwK_xCyR1KG1wC5R"},{url:"/_next/static/chunks/app/api/v1/user/%5Bid%5D/profile/avatar/route-09c2f85c400801e3.js",revision:"Gn2_GgwK_xCyR1KG1wC5R"},{url:"/_next/static/chunks/app/api/v1/user/%5Bid%5D/profile/route-1ac1d4772ef41b0f.js",revision:"Gn2_GgwK_xCyR1KG1wC5R"},{url:"/_next/static/chunks/e37a0b60-b74be3d42787b18d.js",revision:"Gn2_GgwK_xCyR1KG1wC5R"},{url:"/_next/static/chunks/framework-f66176bb897dc684.js",revision:"Gn2_GgwK_xCyR1KG1wC5R"},{url:"/_next/static/chunks/main-app-499b908c1e14996d.js",revision:"Gn2_GgwK_xCyR1KG1wC5R"},{url:"/_next/static/chunks/main-b656d022b7799182.js",revision:"Gn2_GgwK_xCyR1KG1wC5R"},{url:"/_next/static/chunks/pages/_app-6a626577ffa902a4.js",revision:"Gn2_GgwK_xCyR1KG1wC5R"},{url:"/_next/static/chunks/pages/_error-1be831200e60c5c0.js",revision:"Gn2_GgwK_xCyR1KG1wC5R"},{url:"/_next/static/chunks/polyfills-42372ed130431b0a.js",revision:"846118c33b2c0e922d7b3a7676f81f6f"},{url:"/_next/static/chunks/webpack-0933a9779fa8d7e2.js",revision:"Gn2_GgwK_xCyR1KG1wC5R"},{url:"/_next/static/css/05cc92c67fe67fb5.css",revision:"05cc92c67fe67fb5"},{url:"/_next/static/css/84512d98ae0060e4.css",revision:"84512d98ae0060e4"},{url:"/_next/static/media/26a46d62cd723877-s.woff2",revision:"befd9c0fdfa3d8a645d5f95717ed6420"},{url:"/_next/static/media/55c55f0601d81cf3-s.woff2",revision:"43828e14271c77b87e3ed582dbff9f74"},{url:"/_next/static/media/581909926a08bbc8-s.woff2",revision:"f0b86e7c24f455280b8df606b89af891"},{url:"/_next/static/media/6d93bde91c0c2823-s.woff2",revision:"621a07228c8ccbfd647918f1021b4868"},{url:"/_next/static/media/97e0cb1ae144a2a9-s.woff2",revision:"e360c61c5bd8d90639fd4503c829c2dc"},{url:"/_next/static/media/a34f9d1faa5f3315-s.p.woff2",revision:"d4fe31e6a2aebc06b8d6e558c9141119"},{url:"/_next/static/media/df0a9ae256c0569c-s.woff2",revision:"d54db44de5ccb18886ece2fda72bdfe0"},{url:"/_next/static/media/logo.af74964e.png",revision:"47b84a04dca72c139e6f1c360998ae6e"},{url:"/manifest.json",revision:"180c42e2d45dc89fa94620a7942e4823"},{url:"/openapi.yaml",revision:"c34210dd6f89d2cf3bfd0b2f3485739e"},{url:"/service-worker.js",revision:"4f5b998def3df2d4a67f307e8fb251ad"},{url:"/static/algolia.png",revision:"d36577ab9bc617c8545cff97181861b7"},{url:"/static/images/templates/products/milk-template.webp",revision:"0bc05700930282f2b066755cf7bc6969"},{url:"/static/logo.png",revision:"47b84a04dca72c139e6f1c360998ae6e"}],{ignoreURLParametersMatching:[/^utm_/,/^fbclid$/]}),e.cleanupOutdatedCaches(),e.registerRoute("/",new e.NetworkFirst({cacheName:"start-url",plugins:[{cacheWillUpdate:function(e){return _ref.apply(this,arguments)}}]}),"GET"),e.registerRoute(/^https:\/\/fonts\.(?:gstatic)\.com\/.*/i,new e.CacheFirst({cacheName:"google-fonts-webfonts",plugins:[new e.ExpirationPlugin({maxEntries:4,maxAgeSeconds:31536e3})]}),"GET"),e.registerRoute(/^https:\/\/fonts\.(?:googleapis)\.com\/.*/i,new e.StaleWhileRevalidate({cacheName:"google-fonts-stylesheets",plugins:[new e.ExpirationPlugin({maxEntries:4,maxAgeSeconds:604800})]}),"GET"),e.registerRoute(/\.(?:eot|otf|ttc|ttf|woff|woff2|font.css)$/i,new e.StaleWhileRevalidate({cacheName:"static-font-assets",plugins:[new e.ExpirationPlugin({maxEntries:4,maxAgeSeconds:604800})]}),"GET"),e.registerRoute(/\.(?:jpg|jpeg|gif|png|svg|ico|webp)$/i,new e.StaleWhileRevalidate({cacheName:"static-image-assets",plugins:[new e.ExpirationPlugin({maxEntries:64,maxAgeSeconds:2592e3})]}),"GET"),e.registerRoute(/\/_next\/static.+\.js$/i,new e.CacheFirst({cacheName:"next-static-js-assets",plugins:[new e.ExpirationPlugin({maxEntries:64,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\/_next\/image\?url=.+$/i,new e.StaleWhileRevalidate({cacheName:"next-image",plugins:[new e.ExpirationPlugin({maxEntries:64,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:mp3|wav|ogg)$/i,new e.CacheFirst({cacheName:"static-audio-assets",plugins:[new e.RangeRequestsPlugin,new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:mp4|webm)$/i,new e.CacheFirst({cacheName:"static-video-assets",plugins:[new e.RangeRequestsPlugin,new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:js)$/i,new e.StaleWhileRevalidate({cacheName:"static-js-assets",plugins:[new e.ExpirationPlugin({maxEntries:48,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:css|less)$/i,new e.StaleWhileRevalidate({cacheName:"static-style-assets",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\/_next\/data\/.+\/.+\.json$/i,new e.StaleWhileRevalidate({cacheName:"next-data",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/\.(?:json|xml|csv)$/i,new e.NetworkFirst({cacheName:"static-data-assets",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute((function(e){var s=e.sameOrigin,n=e.url.pathname;return!(!s||n.startsWith("/api/auth/callback")||!n.startsWith("/api/"))}),new e.NetworkFirst({cacheName:"apis",networkTimeoutSeconds:10,plugins:[new e.ExpirationPlugin({maxEntries:16,maxAgeSeconds:86400})]}),"GET"),e.registerRoute((function(e){var s=e.request,n=e.url.pathname,a=e.sameOrigin;return"1"===s.headers.get("RSC")&&"1"===s.headers.get("Next-Router-Prefetch")&&a&&!n.startsWith("/api/")}),new e.NetworkFirst({cacheName:"pages-rsc-prefetch",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute((function(e){var s=e.request,n=e.url.pathname,a=e.sameOrigin;return"1"===s.headers.get("RSC")&&a&&!n.startsWith("/api/")}),new e.NetworkFirst({cacheName:"pages-rsc",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute((function(e){var s=e.url.pathname;return e.sameOrigin&&!s.startsWith("/api/")}),new e.NetworkFirst({cacheName:"pages",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET"),e.registerRoute((function(e){return!e.sameOrigin}),new e.NetworkFirst({cacheName:"cross-origin",networkTimeoutSeconds:10,plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:3600})]}),"GET")})); diff --git a/pcomparator/src/app/[locale]/globals.css b/pcomparator/src/app/[locale]/globals.css index 1178265..1fdd858 100644 --- a/pcomparator/src/app/[locale]/globals.css +++ b/pcomparator/src/app/[locale]/globals.css @@ -4,7 +4,7 @@ div[data-overlay-container="true"] { @apply flex flex-col flex-1; - @apply min-h-dvh w-full bg-gradient-to-br dark:from-[#1f121b] dark:via-[#0c1820] dark:via-80% dark:to-[#081917] from-indigo-50 via-white to-primary-200; + @apply min-h-dvh w-full bg-gradient-to-b dark:from-[#1f121b] dark:via-[#0c1820] dark:via-80% dark:to-[#081917] from-indigo-50 via-white to-primary-200; } .PhoneInput { diff --git a/pcomparator/src/app/[locale]/layout.tsx b/pcomparator/src/app/[locale]/layout.tsx index 2b0fe4f..3dad7e8 100644 --- a/pcomparator/src/app/[locale]/layout.tsx +++ b/pcomparator/src/app/[locale]/layout.tsx @@ -7,6 +7,7 @@ import { pcomparatorMetadata } from "~/core/metadata"; import { type NextPageProps, withLinguiLayout } from "~/core/withLinguiLayout"; import "react-toastify/dist/ReactToastify.css"; import "./globals.css"; +import { InstallPWA } from "~/core/pwa/Install"; const inter = Inter({ subsets: ["latin"] }); @@ -19,7 +20,10 @@ const RootLayout = ({ children, locale }: NextPageProps) => { - {children} + + + {children} + diff --git a/pcomparator/src/app/manifest.ts b/pcomparator/src/app/manifest.ts index 2b0739f..ed5741f 100644 --- a/pcomparator/src/app/manifest.ts +++ b/pcomparator/src/app/manifest.ts @@ -2,22 +2,25 @@ import type { MetadataRoute } from "next"; export default (): MetadataRoute.Manifest => { return { - name: "PComparator", - short_name: "PComparator", - description: "PComparator is the price comparator for foods, cosmetic and more", + name: "Daizl - Compare Prices Easily", + short_name: "Deazl", + description: + "Daizl is a web app that helps you compare prices for food, cosmetics, and more to find the best deals near you.", start_url: "/", display: "standalone", - background_color: "#000", - theme_color: "#000", + background_color: "#eef2ff", + theme_color: "#eef2ff", orientation: "portrait", dir: "ltr", lang: "en", + id: "/", screenshots: [ { src: "/static/logo.png", sizes: "512x512", type: "image/png" - } + }, + { form_factor: "wide", src: "/static/logo.png", sizes: "512x512", type: "image/png" } ], icons: [ { @@ -25,6 +28,13 @@ export default (): MetadataRoute.Manifest => { sizes: "512x512", type: "image/png" } - ] + ], + related_applications: [ + { + platform: "webapp", + url: "https://daizl.fr/manifest.webmanifest" + } + ], + prefer_related_applications: true }; }; diff --git a/pcomparator/src/app/robots.txt b/pcomparator/src/app/robots.txt index ed978d4..e8f1b3b 100644 --- a/pcomparator/src/app/robots.txt +++ b/pcomparator/src/app/robots.txt @@ -2,4 +2,4 @@ User-Agent: * Allow: / Disallow: /private/ -Sitemap: https://pcomparator.vercel.app/sitemap.xml \ No newline at end of file +Sitemap: https://deazl.fr/sitemap.xml \ No newline at end of file diff --git a/pcomparator/src/applications/Searchbar/Ui/SearchBarcode/SearchBarcode.tsx b/pcomparator/src/applications/Searchbar/Ui/SearchBarcode/SearchBarcode.tsx index 84aef74..5d4848d 100644 --- a/pcomparator/src/applications/Searchbar/Ui/SearchBarcode/SearchBarcode.tsx +++ b/pcomparator/src/applications/Searchbar/Ui/SearchBarcode/SearchBarcode.tsx @@ -34,7 +34,7 @@ export const SearchBarcode = ({ onNewProduct, onNoPrices }: SearchBarcodeProps) onPress={onOpen} radius="full" variant="faded" - className="p-7 w-18 h-18 -mt-8 border-none shadow-medium" + className="p-7 w-18 h-18 -mt-8 border-none shadow-[0_5px_10px_1px_rgba(0,0,0,.2)]" isIconOnly /> diff --git a/pcomparator/src/components/Tabbar/Tabbar.tsx b/pcomparator/src/components/Tabbar/Tabbar.tsx index f42417c..95750c4 100644 --- a/pcomparator/src/components/Tabbar/Tabbar.tsx +++ b/pcomparator/src/components/Tabbar/Tabbar.tsx @@ -10,7 +10,7 @@ export interface TabbarProps { } export const Tabbar = ({ mainButton }: TabbarProps) => ( -
+
+ + + + ) : webInstallPrompt ? ( + <> + + Install Our App for a Better Experience! + + +

+ Get faster access, work offline, and enjoy a smoother experience. +

+
    +
  • + + Instant access with one tap + +
  • +
  • + + No need for app store downloads + +
  • +
  • + + Works offline and loads faster + +
  • +
  • + + Stay updated with notifications + +
  • +
+
+ + + + + + ) : null} + + + ); +}; + +export const InstallPWA = dynamic(() => Promise.resolve(InstallPrompt), { + ssr: false +}); diff --git a/pcomparator/src/core/pwa/useIos.ts b/pcomparator/src/core/pwa/useIos.ts new file mode 100644 index 0000000..b01bd83 --- /dev/null +++ b/pcomparator/src/core/pwa/useIos.ts @@ -0,0 +1,23 @@ +import useShouldShowPrompt from "~/core/pwa/useShouldShow"; + +const iosInstallPromptedAt = "iosInstallPromptedAt"; + +const isIOS = (): boolean => { + // @ts-ignore + if (navigator.standalone) { + //user has already installed the app + return false; + } + const ua = window.navigator.userAgent; + const isIPad = !!ua.match(/iPad/i); + const isIPhone = !!ua.match(/iPhone/i); + return isIPad || isIPhone; +}; + +const useIosInstallPrompt = (): [boolean, () => void] => { + const [userShouldBePromptedToInstall, handleUserSeeingInstallPrompt] = + useShouldShowPrompt(iosInstallPromptedAt); + + return [isIOS() && userShouldBePromptedToInstall, handleUserSeeingInstallPrompt]; +}; +export default useIosInstallPrompt; diff --git a/pcomparator/src/core/pwa/useShouldShow.ts b/pcomparator/src/core/pwa/useShouldShow.ts new file mode 100644 index 0000000..3809b4d --- /dev/null +++ b/pcomparator/src/core/pwa/useShouldShow.ts @@ -0,0 +1,35 @@ +import moment from "moment"; +import { useState } from "react"; + +const getInstallPromptLastSeenAt = (promptName: string): string => localStorage.getItem(promptName)!; + +const setInstallPromptSeenToday = (promptName: string): void => { + const today = moment().toISOString(); + localStorage.setItem(promptName, today); +}; + +function getUserShouldBePromptedToInstall( + promptName: string, + daysToWaitBeforePromptingAgain: number +): boolean { + const lastPrompt = moment(getInstallPromptLastSeenAt(promptName)); + const daysSinceLastPrompt = moment().diff(lastPrompt, "days"); + return Number.isNaN(daysSinceLastPrompt) || daysSinceLastPrompt > daysToWaitBeforePromptingAgain; +} + +const useShouldShowPrompt = ( + promptName: string, + daysToWaitBeforePromptingAgain = 30 +): [boolean, () => void] => { + const [userShouldBePromptedToInstall, setUserShouldBePromptedToInstall] = useState( + getUserShouldBePromptedToInstall(promptName, daysToWaitBeforePromptingAgain) + ); + + const handleUserSeeingInstallPrompt = () => { + setUserShouldBePromptedToInstall(false); + setInstallPromptSeenToday(promptName); + }; + + return [userShouldBePromptedToInstall, handleUserSeeingInstallPrompt]; +}; +export default useShouldShowPrompt; diff --git a/pcomparator/src/core/pwa/useWebInstall.ts b/pcomparator/src/core/pwa/useWebInstall.ts new file mode 100644 index 0000000..c5d38b5 --- /dev/null +++ b/pcomparator/src/core/pwa/useWebInstall.ts @@ -0,0 +1,42 @@ +"use client"; + +import { useEffect, useState } from "react"; +import useShouldShowPrompt from "~/core/pwa/useShouldShow"; + +const webInstallPromptedAt = "webInstallPromptedAt"; + +const useWebInstallPrompt = (): [any, () => void, () => void] => { + const [installPromptEvent, setInstallPromptEvent] = useState(null); + const [userShouldBePromptedToInstall, handleUserSeeingInstallPrompt] = + useShouldShowPrompt(webInstallPromptedAt); + + useEffect(() => { + const beforeInstallPromptHandler = (event: any) => { + event.preventDefault(); + + if (userShouldBePromptedToInstall) { + setInstallPromptEvent(event); + } + }; + window.addEventListener("beforeinstallprompt", beforeInstallPromptHandler); + return () => window.removeEventListener("beforeinstallprompt", beforeInstallPromptHandler); + }, [userShouldBePromptedToInstall]); + + const handleInstallDeclined = () => { + handleUserSeeingInstallPrompt(); + setInstallPromptEvent(null); + }; + + const handleInstallAccepted = () => { + installPromptEvent.prompt(); + + installPromptEvent.userChoice.then((choice: any) => { + if (choice.outcome !== "accepted") { + handleUserSeeingInstallPrompt(); + } + setInstallPromptEvent(null); + }); + }; + return [installPromptEvent, handleInstallDeclined, handleInstallAccepted]; +}; +export default useWebInstallPrompt; diff --git a/pcomparator/src/middleware.ts b/pcomparator/src/middleware.ts index bdbc6c4..28c1972 100644 --- a/pcomparator/src/middleware.ts +++ b/pcomparator/src/middleware.ts @@ -36,5 +36,5 @@ export default async (request: NextRequest) => { }; export const config = { - matcher: ["/((?!api|_next/static|_next/image|favicon.ico|manifest|static/*).*)"] + matcher: ["/((?!api|_next/static|_next/image|favicon.ico|manifest|static/*|robots|sw|workbox-*).*)"] }; diff --git a/pcomparator/src/translations/messages/en.po b/pcomparator/src/translations/messages/en.po index ff03ac9..f17022d 100644 --- a/pcomparator/src/translations/messages/en.po +++ b/pcomparator/src/translations/messages/en.po @@ -79,6 +79,7 @@ msgstr "Click on the avatar to upload a custom one from your files." msgid "Close" msgstr "Close" +#: src/applications/Prices/Ui/NewPrice/FormSteps/Step4/Location.tsx #: src/applications/Prices/Ui/NewQuickPrice/FormSteps/Location.tsx msgid "Custom location" msgstr "Custom location" @@ -141,6 +142,11 @@ msgstr "Environment" msgid "Fullname updated" msgstr "Fullname updated" +#: src/core/pwa/Install.tsx +#: src/core/pwa/Install.tsx +msgid "Get faster access, work offline, and enjoy a smoother experience." +msgstr "Get faster access, work offline, and enjoy a smoother experience." + #: src/applications/Prices/Ui/ListPrices/CardPrice/SeeMoreModal.tsx msgid "Health" msgstr "Health" @@ -153,6 +159,11 @@ msgstr "Hello {0}" msgid "I understand, delete my account" msgstr "I understand, delete my account" +#: src/core/pwa/Install.tsx +#: src/core/pwa/Install.tsx +msgid "Install Our App for a Better Experience!" +msgstr "Install Our App for a Better Experience!" + #: src/applications/Profile/Ui/Settings/DisplayName.tsx msgid "Invalid display name." msgstr "Invalid display name." @@ -169,7 +180,8 @@ msgstr "Light" msgid "Location" msgstr "Location" -#: src/applications/Products/Ui/NewProduct/NewProduct.tsx +#: src/core/pwa/Install.tsx +#: src/core/pwa/Install.tsx msgid "Maybe later" msgstr "Maybe later" @@ -177,7 +189,12 @@ msgstr "Maybe later" msgid "My Prices" msgstr "My Prices" +#: src/applications/Prices/Ui/NewPrice/FormSteps/Step1/TypeBarcode.tsx +#: src/applications/Prices/Ui/NewPrice/FormSteps/Step2/Price.tsx +#: src/applications/Prices/Ui/NewPrice/FormSteps/Step3/Proof.tsx +#: src/applications/Prices/Ui/NewPrice/FormSteps/Step4/Location.tsx #: src/applications/Prices/Ui/NewQuickPrice/FormSteps/Location.tsx +#: src/components/Form/FormActions.tsx msgid "Next" msgstr "Next" @@ -214,10 +231,15 @@ msgstr "Please enter your full name, or a display name you are comfortable with. msgid "Please use 32 characters at maximum." msgstr "Please use 32 characters at maximum." +#: src/applications/Prices/Ui/NewPrice/FormSteps/Step2/Price.tsx +#: src/applications/Prices/Ui/NewPrice/FormSteps/Step3/Proof.tsx +#: src/applications/Prices/Ui/NewPrice/FormSteps/Step4/Location.tsx #: src/applications/Prices/Ui/NewQuickPrice/FormSteps/Location.tsx msgid "Previous" msgstr "Previous" +#: src/applications/Prices/Ui/NewPrice/FormSteps/Step2/Price.tsx +#: src/applications/Prices/Ui/NewPrice/NewPiceModal.tsx #: src/applications/Prices/Ui/NewQuickPrice/FormSteps/Price.tsx msgid "Price" msgstr "Price" @@ -267,6 +289,7 @@ msgstr "Save" msgid "Scan barcode" msgstr "Scan barcode" +#: src/applications/Prices/Ui/NewPrice/FormSteps/Step4/Location.tsx #: src/applications/Prices/Ui/NewQuickPrice/FormSteps/Location.tsx msgid "Search" msgstr "Search" diff --git a/pcomparator/src/translations/messages/fr.po b/pcomparator/src/translations/messages/fr.po index 8cb05f3..7d809ae 100644 --- a/pcomparator/src/translations/messages/fr.po +++ b/pcomparator/src/translations/messages/fr.po @@ -79,6 +79,7 @@ msgstr "Cliquer sur avatar pour ajouter un depuis vos fichier." msgid "Close" msgstr "Fermer" +#: src/applications/Prices/Ui/NewPrice/FormSteps/Step4/Location.tsx #: src/applications/Prices/Ui/NewQuickPrice/FormSteps/Location.tsx msgid "Custom location" msgstr "Localisation personsalisée" @@ -141,6 +142,11 @@ msgstr "Environnement" msgid "Fullname updated" msgstr "Nom complet mis à jour." +#: src/core/pwa/Install.tsx +#: src/core/pwa/Install.tsx +msgid "Get faster access, work offline, and enjoy a smoother experience." +msgstr "Accédez plus rapidement, travaillez hors ligne et profitez d'une expérience plus fluide." + #: src/applications/Prices/Ui/ListPrices/CardPrice/SeeMoreModal.tsx msgid "Health" msgstr "Santé" @@ -153,6 +159,11 @@ msgstr "Bonjour {0}" msgid "I understand, delete my account" msgstr "Je comprends, supprimez mon compte." +#: src/core/pwa/Install.tsx +#: src/core/pwa/Install.tsx +msgid "Install Our App for a Better Experience!" +msgstr "Installez notre application pour une meilleure expérience !" + #: src/applications/Profile/Ui/Settings/DisplayName.tsx msgid "Invalid display name." msgstr "Nom d'affichage invalide." @@ -169,7 +180,8 @@ msgstr "Clair" msgid "Location" msgstr "Localisation" -#: src/applications/Products/Ui/NewProduct/NewProduct.tsx +#: src/core/pwa/Install.tsx +#: src/core/pwa/Install.tsx msgid "Maybe later" msgstr "Peut-être plus tard" @@ -177,7 +189,12 @@ msgstr "Peut-être plus tard" msgid "My Prices" msgstr "Mes prix" +#: src/applications/Prices/Ui/NewPrice/FormSteps/Step1/TypeBarcode.tsx +#: src/applications/Prices/Ui/NewPrice/FormSteps/Step2/Price.tsx +#: src/applications/Prices/Ui/NewPrice/FormSteps/Step3/Proof.tsx +#: src/applications/Prices/Ui/NewPrice/FormSteps/Step4/Location.tsx #: src/applications/Prices/Ui/NewQuickPrice/FormSteps/Location.tsx +#: src/components/Form/FormActions.tsx msgid "Next" msgstr "Suivant" @@ -214,10 +231,15 @@ msgstr "Veuillez entrer votre nom complet, ou un nom d'affichage avec lequel vou msgid "Please use 32 characters at maximum." msgstr "Veuillez utiliser 32 caractères maximum." +#: src/applications/Prices/Ui/NewPrice/FormSteps/Step2/Price.tsx +#: src/applications/Prices/Ui/NewPrice/FormSteps/Step3/Proof.tsx +#: src/applications/Prices/Ui/NewPrice/FormSteps/Step4/Location.tsx #: src/applications/Prices/Ui/NewQuickPrice/FormSteps/Location.tsx msgid "Previous" msgstr "Précédent" +#: src/applications/Prices/Ui/NewPrice/FormSteps/Step2/Price.tsx +#: src/applications/Prices/Ui/NewPrice/NewPiceModal.tsx #: src/applications/Prices/Ui/NewQuickPrice/FormSteps/Price.tsx msgid "Price" msgstr "Prix" @@ -267,6 +289,7 @@ msgstr "Sauvegarder" msgid "Scan barcode" msgstr "Scanner code-barre" +#: src/applications/Prices/Ui/NewPrice/FormSteps/Step4/Location.tsx #: src/applications/Prices/Ui/NewQuickPrice/FormSteps/Location.tsx msgid "Search" msgstr "Recherche" diff --git a/pcomparator/yarn.lock b/pcomparator/yarn.lock index a3f6e83..7bc28d4 100644 --- a/pcomparator/yarn.lock +++ b/pcomparator/yarn.lock @@ -1669,6 +1669,13 @@ __metadata: languageName: node linkType: hard +"@dotmind/react-use-pwa@npm:^1.0.4": + version: 1.0.4 + resolution: "@dotmind/react-use-pwa@npm:1.0.4" + checksum: e040cd4ed3d50f05d8c416234f21ea208480c1ee3cdff2e1a4edde6d42a2dc3e87d250bea1628d3a50ed787d7669f61c663526b9e0111fb7641d6368978395de + languageName: node + linkType: hard + "@ducanh2912/next-pwa@npm:^10.2.9": version: 10.2.9 resolution: "@ducanh2912/next-pwa@npm:10.2.9" @@ -15710,6 +15717,13 @@ __metadata: languageName: node linkType: hard +"moment@npm:^2.30.1": + version: 2.30.1 + resolution: "moment@npm:2.30.1" + checksum: 859236bab1e88c3e5802afcf797fc801acdbd0ee509d34ea3df6eea21eb6bcc2abd4ae4e4e64aa7c986aa6cba563c6e62806218e6412a765010712e5fa121ba6 + languageName: node + linkType: hard + "moo-color@npm:^1.0.2": version: 1.0.3 resolution: "moo-color@npm:1.0.3" @@ -16971,6 +16985,7 @@ __metadata: "@babel/core": ^7.24.4 "@babel/preset-react": ^7.24.1 "@babel/preset-typescript": ^7.24.1 + "@dotmind/react-use-pwa": ^1.0.4 "@ducanh2912/next-pwa": ^10.2.9 "@imbios/next-pwa": ^1.1.1 "@lingui/cli": ^4.11.0 @@ -17027,6 +17042,7 @@ __metadata: lint-staged: ^15.2.10 lodash: ^4.17.21 lucide-react: ^0.453.0 + moment: ^2.30.1 next: 15.0.0 next-auth: beta next-themes: ^0.3.0