diff --git a/maternal-web/components/children/ChildDialog.tsx b/maternal-web/components/children/ChildDialog.tsx index 2925897..017053d 100644 --- a/maternal-web/components/children/ChildDialog.tsx +++ b/maternal-web/components/children/ChildDialog.tsx @@ -153,6 +153,8 @@ export function ChildDialog({ open, onClose, onSubmit, child, isLoading = false onChange={(url) => setFormData({ ...formData, photoUrl: url })} disabled={isLoading} size={80} + childId={child?.id} + type="profile" /> diff --git a/maternal-web/components/common/PhotoUpload.tsx b/maternal-web/components/common/PhotoUpload.tsx index 5811aa2..c5ef12d 100644 --- a/maternal-web/components/common/PhotoUpload.tsx +++ b/maternal-web/components/common/PhotoUpload.tsx @@ -9,8 +9,10 @@ import { Typography, Paper, Alert, + CircularProgress, } from '@mui/material'; import { PhotoCamera, Person } from '@mui/icons-material'; +import { photosApi } from '@/lib/api/photos'; interface PhotoUploadProps { value: string; @@ -18,6 +20,8 @@ interface PhotoUploadProps { label: string; disabled?: boolean; size?: number; + childId?: string; + type?: string; } export function PhotoUpload({ @@ -25,10 +29,13 @@ export function PhotoUpload({ onChange, label, disabled = false, - size = 100 + size = 100, + childId, + type = 'profile' }: PhotoUploadProps) { const [imageError, setImageError] = useState(false); const [uploadError, setUploadError] = useState(''); + const [uploading, setUploading] = useState(false); const fileInputRef = useRef(null); const handleImageError = () => { @@ -49,29 +56,36 @@ export function PhotoUpload({ return; } - // Validate file size (max 5MB) - const maxSize = 5 * 1024 * 1024; // 5MB + // Validate file size (max 10MB - backend limit) + const maxSize = 10 * 1024 * 1024; // 10MB if (file.size > maxSize) { - setUploadError('Image size must be less than 5MB'); + setUploadError('Image size must be less than 10MB'); return; } - // Convert to base64 - const reader = new FileReader(); - reader.onload = (e) => { - const base64String = e.target?.result as string; - onChange(base64String); + try { + setUploading(true); setUploadError(''); - setImageError(false); - }; - reader.onerror = () => { - setUploadError('Failed to read image file'); - }; - reader.readAsDataURL(file); - // Reset input - if (fileInputRef.current) { - fileInputRef.current.value = ''; + // Upload to backend - it handles Sharp optimization and MinIO storage + const result = await photosApi.uploadPhoto(file, { + childId, + type, + }); + + // Use the optimized URL from backend + onChange(result.photo.url); + setImageError(false); + } catch (error: any) { + console.error('Photo upload failed:', error); + setUploadError(error.response?.data?.message || 'Failed to upload photo'); + } finally { + setUploading(false); + + // Reset input + if (fileInputRef.current) { + fileInputRef.current.value = ''; + } } }; @@ -126,7 +140,7 @@ export function PhotoUpload({ accept="image/*" style={{ display: 'none' }} onChange={handleFileSelect} - disabled={disabled} + disabled={disabled || uploading} /> - + {uploading ? ( + + ) : ( + + )} @@ -156,8 +174,12 @@ export function PhotoUpload({ fullWidth size="small" placeholder="https://example.com/photo.jpg" - disabled={disabled} - helperText="Click camera to upload or paste an image URL" + disabled={disabled || uploading} + helperText={ + uploading + ? 'Uploading and optimizing image...' + : 'Click camera to upload (auto-optimized) or paste URL' + } /> diff --git a/maternal-web/lib/api/photos.ts b/maternal-web/lib/api/photos.ts new file mode 100644 index 0000000..b7fc4d8 --- /dev/null +++ b/maternal-web/lib/api/photos.ts @@ -0,0 +1,48 @@ +import apiClient from './client'; + +export interface PhotoUploadResult { + photo: { + id: string; + url: string; + thumbnailUrl?: string; + originalUrl?: string; + storageKey: string; + }; +} + +export const photosApi = { + /** + * Upload a photo for profile/child + * Uses multipart/form-data to send file to backend + * Backend handles image optimization via Sharp and storage via MinIO + */ + uploadPhoto: async ( + file: File, + options?: { + childId?: string; + type?: string; + caption?: string; + } + ): Promise => { + const formData = new FormData(); + formData.append('photo', file); + + if (options?.childId) { + formData.append('childId', options.childId); + } + if (options?.type) { + formData.append('type', options.type); + } + if (options?.caption) { + formData.append('caption', options.caption); + } + + const response = await apiClient.post('/api/v1/photos/upload', formData, { + headers: { + 'Content-Type': 'multipart/form-data', + }, + }); + + return response.data.data; + }, +}; diff --git a/maternal-web/public/sw.js b/maternal-web/public/sw.js index 9217faa..e6fe170 100644 --- a/maternal-web/public/sw.js +++ b/maternal-web/public/sw.js @@ -1 +1 @@ -if(!self.define){let e,s={};const a=(a,c)=>(a=new URL(a+".js",c).href,s[a]||new Promise(s=>{if("document"in self){const e=document.createElement("script");e.src=a,e.onload=s,document.head.appendChild(e)}else e=a,importScripts(a),s()}).then(()=>{let e=s[a];if(!e)throw new Error(`Module ${a} didn’t register its module`);return e}));self.define=(c,i)=>{const n=e||("document"in self?document.currentScript.src:"")||location.href;if(s[n])return;let t={};const f=e=>a(e,n),r={module:{uri:n},exports:t,require:f};s[n]=Promise.all(c.map(e=>r[e]||f(e))).then(e=>(i(...e),t))}}define(["./workbox-4d767a27"],function(e){"use strict";importScripts(),self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"/_next/app-build-manifest.json",revision:"a44df32a02f8cc4c43505ecc0944d8f0"},{url:"/_next/static/Mvkhr1bycaL0Filj2LC4z/_buildManifest.js",revision:"8f0f5ce83e0c1a8bb7ed8c5093a55c39"},{url:"/_next/static/Mvkhr1bycaL0Filj2LC4z/_ssgManifest.js",revision:"b6652df95db52feb4daf4eca35380933"},{url:"/_next/static/chunks/101-3dd0627909cd6c22.js",revision:"3dd0627909cd6c22"},{url:"/_next/static/chunks/1063-f889ee292f8f15b5.js",revision:"f889ee292f8f15b5"},{url:"/_next/static/chunks/1123-1d08a95481112410.js",revision:"1d08a95481112410"},{url:"/_next/static/chunks/1213-7820689c8a23df1d.js",revision:"7820689c8a23df1d"},{url:"/_next/static/chunks/1255-b2f7fd83e387a9e1.js",revision:"b2f7fd83e387a9e1"},{url:"/_next/static/chunks/1280-c37f3ad0d154b82b.js",revision:"c37f3ad0d154b82b"},{url:"/_next/static/chunks/1586-f0590617c4477631.js",revision:"f0590617c4477631"},{url:"/_next/static/chunks/1863-7231108310f72246.js",revision:"7231108310f72246"},{url:"/_next/static/chunks/2262-26293d6453fcc927.js",revision:"26293d6453fcc927"},{url:"/_next/static/chunks/2757-a8c5bc35e392204d.js",revision:"a8c5bc35e392204d"},{url:"/_next/static/chunks/3039-0e9bf08230c8ee7b.js",revision:"0e9bf08230c8ee7b"},{url:"/_next/static/chunks/3472-0cbeb387c6b7d2f9.js",revision:"0cbeb387c6b7d2f9"},{url:"/_next/static/chunks/3762-1c91083fb1a622c0.js",revision:"1c91083fb1a622c0"},{url:"/_next/static/chunks/416.e8f04b8e9d246c5d.js",revision:"e8f04b8e9d246c5d"},{url:"/_next/static/chunks/4296-d8fbf75df3b777b4.js",revision:"d8fbf75df3b777b4"},{url:"/_next/static/chunks/4589-ddaaeca1ea084b22.js",revision:"ddaaeca1ea084b22"},{url:"/_next/static/chunks/4871.a78304faf25ea37e.js",revision:"a78304faf25ea37e"},{url:"/_next/static/chunks/4bd1b696-100b9d70ed4e49c1.js",revision:"100b9d70ed4e49c1"},{url:"/_next/static/chunks/5125-c990fc036d2a6ce4.js",revision:"c990fc036d2a6ce4"},{url:"/_next/static/chunks/5204-40bcee73ecd8ab8c.js",revision:"40bcee73ecd8ab8c"},{url:"/_next/static/chunks/5352-2d1b054130cf56bf.js",revision:"2d1b054130cf56bf"},{url:"/_next/static/chunks/5380-9004e1ac3565daca.js",revision:"9004e1ac3565daca"},{url:"/_next/static/chunks/5385-7ecda8e4ba984edc.js",revision:"7ecda8e4ba984edc"},{url:"/_next/static/chunks/5482-7535aa0aab02d518.js",revision:"7535aa0aab02d518"},{url:"/_next/static/chunks/5769-41ddcfc7762d7501.js",revision:"41ddcfc7762d7501"},{url:"/_next/static/chunks/5786-300f6f4e5c444b8e.js",revision:"300f6f4e5c444b8e"},{url:"/_next/static/chunks/5942.e3bd8fc7fc1e4596.js",revision:"e3bd8fc7fc1e4596"},{url:"/_next/static/chunks/6088-c165c565edce02be.js",revision:"c165c565edce02be"},{url:"/_next/static/chunks/6286-086a26f8f0ae31b4.js",revision:"086a26f8f0ae31b4"},{url:"/_next/static/chunks/6293-a9927cacf03898b6.js",revision:"a9927cacf03898b6"},{url:"/_next/static/chunks/670-a4ca0f366ee779f5.js",revision:"a4ca0f366ee779f5"},{url:"/_next/static/chunks/6847-ce99bc721adda9c4.js",revision:"ce99bc721adda9c4"},{url:"/_next/static/chunks/6873-ff265086321345c8.js",revision:"ff265086321345c8"},{url:"/_next/static/chunks/710-7e96cbf5d461482a.js",revision:"7e96cbf5d461482a"},{url:"/_next/static/chunks/7332-fd60cdf555c2ea53.js",revision:"fd60cdf555c2ea53"},{url:"/_next/static/chunks/7359-1abfb9f346309354.js",revision:"1abfb9f346309354"},{url:"/_next/static/chunks/7567-0776b78d8fa131c0.js",revision:"0776b78d8fa131c0"},{url:"/_next/static/chunks/7741-0af8b5a61d8e63d3.js",revision:"0af8b5a61d8e63d3"},{url:"/_next/static/chunks/7855-72c79224370eff7b.js",revision:"72c79224370eff7b"},{url:"/_next/static/chunks/787-032067ae978e62a8.js",revision:"032067ae978e62a8"},{url:"/_next/static/chunks/7917-630571e0a7d1019f.js",revision:"630571e0a7d1019f"},{url:"/_next/static/chunks/8241-eaf1b9c6054e9ad8.js",revision:"eaf1b9c6054e9ad8"},{url:"/_next/static/chunks/8286-7d0f4d46ecab678b.js",revision:"7d0f4d46ecab678b"},{url:"/_next/static/chunks/8466-ffa71cea7998f777.js",revision:"ffa71cea7998f777"},{url:"/_next/static/chunks/8721-4fdab69857d188e9.js",revision:"4fdab69857d188e9"},{url:"/_next/static/chunks/8746-92ff3ad56eb06d6e.js",revision:"92ff3ad56eb06d6e"},{url:"/_next/static/chunks/8930.1853f82129e20bef.js",revision:"1853f82129e20bef"},{url:"/_next/static/chunks/9205-f540995b767df00b.js",revision:"f540995b767df00b"},{url:"/_next/static/chunks/9397-40b8ac68e22a4d87.js",revision:"40b8ac68e22a4d87"},{url:"/_next/static/chunks/9811-2efcf2d216d2373b.js",revision:"2efcf2d216d2373b"},{url:"/_next/static/chunks/app/(auth)/forgot-password/page-468863a70b7f33bd.js",revision:"468863a70b7f33bd"},{url:"/_next/static/chunks/app/(auth)/login/page-c220f5f8f2ed10f6.js",revision:"c220f5f8f2ed10f6"},{url:"/_next/static/chunks/app/(auth)/onboarding/page-523c4adefb919140.js",revision:"523c4adefb919140"},{url:"/_next/static/chunks/app/(auth)/register/page-ab3799fa4df2090e.js",revision:"ab3799fa4df2090e"},{url:"/_next/static/chunks/app/(auth)/reset-password/page-b3351aa7bf1d737f.js",revision:"b3351aa7bf1d737f"},{url:"/_next/static/chunks/app/_not-found/page-95f11f5fe94340f1.js",revision:"95f11f5fe94340f1"},{url:"/_next/static/chunks/app/activities/page-4f906e4431600a36.js",revision:"4f906e4431600a36"},{url:"/_next/static/chunks/app/ai-assistant/page-31869b104c2893be.js",revision:"31869b104c2893be"},{url:"/_next/static/chunks/app/analytics/page-ab71bfe91aef0dfd.js",revision:"ab71bfe91aef0dfd"},{url:"/_next/static/chunks/app/api/ai/chat/route-a631d97a33877f8a.js",revision:"a631d97a33877f8a"},{url:"/_next/static/chunks/app/api/auth/login/route-a631d97a33877f8a.js",revision:"a631d97a33877f8a"},{url:"/_next/static/chunks/app/api/auth/password-reset/route-a631d97a33877f8a.js",revision:"a631d97a33877f8a"},{url:"/_next/static/chunks/app/api/auth/register/route-a631d97a33877f8a.js",revision:"a631d97a33877f8a"},{url:"/_next/static/chunks/app/api/health/route-a631d97a33877f8a.js",revision:"a631d97a33877f8a"},{url:"/_next/static/chunks/app/api/tracking/feeding/route-a631d97a33877f8a.js",revision:"a631d97a33877f8a"},{url:"/_next/static/chunks/app/api/voice/transcribe/route-a631d97a33877f8a.js",revision:"a631d97a33877f8a"},{url:"/_next/static/chunks/app/children/page-1c8ad6cc6e0935cf.js",revision:"1c8ad6cc6e0935cf"},{url:"/_next/static/chunks/app/family/page-2f110249fcfd1412.js",revision:"2f110249fcfd1412"},{url:"/_next/static/chunks/app/history/page-7cab5f74bb875f16.js",revision:"7cab5f74bb875f16"},{url:"/_next/static/chunks/app/insights/page-dd390b978f516172.js",revision:"dd390b978f516172"},{url:"/_next/static/chunks/app/layout-1c9d8110b20dfde0.js",revision:"1c9d8110b20dfde0"},{url:"/_next/static/chunks/app/logout/page-359b0e371fd55c32.js",revision:"359b0e371fd55c32"},{url:"/_next/static/chunks/app/offline/page-28c005360c2b2736.js",revision:"28c005360c2b2736"},{url:"/_next/static/chunks/app/page-b9e045df422df68b.js",revision:"b9e045df422df68b"},{url:"/_next/static/chunks/app/settings/page-88fcf9c58063da97.js",revision:"88fcf9c58063da97"},{url:"/_next/static/chunks/app/track/activity/page-075cf736b89c38e4.js",revision:"075cf736b89c38e4"},{url:"/_next/static/chunks/app/track/diaper/page-8bfd33a415e648a5.js",revision:"8bfd33a415e648a5"},{url:"/_next/static/chunks/app/track/feeding/page-94ea6af8da6d4df3.js",revision:"94ea6af8da6d4df3"},{url:"/_next/static/chunks/app/track/medicine/page-98485267d91dd81f.js",revision:"98485267d91dd81f"},{url:"/_next/static/chunks/app/track/page-df6b6a1084e8d8c5.js",revision:"df6b6a1084e8d8c5"},{url:"/_next/static/chunks/app/track/sleep/page-b14029bd2898d59c.js",revision:"b14029bd2898d59c"},{url:"/_next/static/chunks/framework-bd61ec64032c2de7.js",revision:"bd61ec64032c2de7"},{url:"/_next/static/chunks/main-520e5ec2d671abe7.js",revision:"520e5ec2d671abe7"},{url:"/_next/static/chunks/main-app-02fc3649960ba6c7.js",revision:"02fc3649960ba6c7"},{url:"/_next/static/chunks/pages/_app-4b3fb5e477a0267f.js",revision:"4b3fb5e477a0267f"},{url:"/_next/static/chunks/pages/_error-c970d8b55ace1b48.js",revision:"c970d8b55ace1b48"},{url:"/_next/static/chunks/polyfills-42372ed130431b0a.js",revision:"846118c33b2c0e922d7b3a7676f81f6f"},{url:"/_next/static/chunks/webpack-ad987399c7124b46.js",revision:"ad987399c7124b46"},{url:"/_next/static/css/0e32a1f7dc037ce2.css",revision:"0e32a1f7dc037ce2"},{url:"/_next/static/media/19cfc7226ec3afaa-s.woff2",revision:"9dda5cfc9a46f256d0e131bb535e46f8"},{url:"/_next/static/media/21350d82a1f187e9-s.woff2",revision:"4e2553027f1d60eff32898367dd4d541"},{url:"/_next/static/media/8e9860b6e62d6359-s.woff2",revision:"01ba6c2a184b8cba08b0d57167664d75"},{url:"/_next/static/media/ba9851c3c22cd980-s.woff2",revision:"9e494903d6b0ffec1a1e14d34427d44d"},{url:"/_next/static/media/c5fe6dc8356a8c31-s.woff2",revision:"027a89e9ab733a145db70f09b8a18b42"},{url:"/_next/static/media/df0a9ae256c0569c-s.woff2",revision:"d54db44de5ccb18886ece2fda72bdfe0"},{url:"/_next/static/media/e4af272ccee01ff0-s.p.woff2",revision:"65850a373e258f1c897a2b3d75eb74de"},{url:"/icons/icon-128x128.png",revision:"d41d8cd98f00b204e9800998ecf8427e"},{url:"/icons/icon-144x144.png",revision:"d41d8cd98f00b204e9800998ecf8427e"},{url:"/icons/icon-152x152.png",revision:"d41d8cd98f00b204e9800998ecf8427e"},{url:"/icons/icon-192x192.png",revision:"d41d8cd98f00b204e9800998ecf8427e"},{url:"/icons/icon-384x384.png",revision:"d41d8cd98f00b204e9800998ecf8427e"},{url:"/icons/icon-512x512.png",revision:"d41d8cd98f00b204e9800998ecf8427e"},{url:"/icons/icon-72x72.png",revision:"d41d8cd98f00b204e9800998ecf8427e"},{url:"/icons/icon-96x96.png",revision:"d41d8cd98f00b204e9800998ecf8427e"},{url:"/manifest.json",revision:"5be5ec81beca107e804b38758d51abd5"},{url:"/next.svg",revision:"8e061864f388b47f33a1c3780831193e"},{url:"/vercel.svg",revision:"61c6b19abff40ea7acd577be818f3976"}],{ignoreURLParametersMatching:[]}),e.cleanupOutdatedCaches(),e.registerRoute("/",new e.NetworkFirst({cacheName:"start-url",plugins:[{cacheWillUpdate:async({request:e,response:s,event:a,state:c})=>s&&"opaqueredirect"===s.type?new Response(s.body,{status:200,statusText:"OK",headers:s.headers}):s}]}),"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: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)$/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:32,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(/\/api\/.*$/i,new e.NetworkFirst({cacheName:"apis",networkTimeoutSeconds:10,plugins:[new e.ExpirationPlugin({maxEntries:16,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/.*/i,new e.NetworkFirst({cacheName:"others",networkTimeoutSeconds:10,plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET")}); +if(!self.define){let e,s={};const a=(a,c)=>(a=new URL(a+".js",c).href,s[a]||new Promise(s=>{if("document"in self){const e=document.createElement("script");e.src=a,e.onload=s,document.head.appendChild(e)}else e=a,importScripts(a),s()}).then(()=>{let e=s[a];if(!e)throw new Error(`Module ${a} didn’t register its module`);return e}));self.define=(c,i)=>{const n=e||("document"in self?document.currentScript.src:"")||location.href;if(s[n])return;let t={};const f=e=>a(e,n),r={module:{uri:n},exports:t,require:f};s[n]=Promise.all(c.map(e=>r[e]||f(e))).then(e=>(i(...e),t))}}define(["./workbox-4d767a27"],function(e){"use strict";importScripts(),self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"/_next/app-build-manifest.json",revision:"e3fccce3b4582f0f15716c893b2abd1f"},{url:"/_next/static/DNH6u4loHbxXTRIXsE5br/_buildManifest.js",revision:"8f0f5ce83e0c1a8bb7ed8c5093a55c39"},{url:"/_next/static/DNH6u4loHbxXTRIXsE5br/_ssgManifest.js",revision:"b6652df95db52feb4daf4eca35380933"},{url:"/_next/static/chunks/101-3dd0627909cd6c22.js",revision:"3dd0627909cd6c22"},{url:"/_next/static/chunks/1063-f889ee292f8f15b5.js",revision:"f889ee292f8f15b5"},{url:"/_next/static/chunks/1123-1d08a95481112410.js",revision:"1d08a95481112410"},{url:"/_next/static/chunks/1213-7820689c8a23df1d.js",revision:"7820689c8a23df1d"},{url:"/_next/static/chunks/1255-b2f7fd83e387a9e1.js",revision:"b2f7fd83e387a9e1"},{url:"/_next/static/chunks/1280-c37f3ad0d154b82b.js",revision:"c37f3ad0d154b82b"},{url:"/_next/static/chunks/1586-f0590617c4477631.js",revision:"f0590617c4477631"},{url:"/_next/static/chunks/1863-7231108310f72246.js",revision:"7231108310f72246"},{url:"/_next/static/chunks/2262-26293d6453fcc927.js",revision:"26293d6453fcc927"},{url:"/_next/static/chunks/2757-a8c5bc35e392204d.js",revision:"a8c5bc35e392204d"},{url:"/_next/static/chunks/3039-0e9bf08230c8ee7b.js",revision:"0e9bf08230c8ee7b"},{url:"/_next/static/chunks/3472-0cbeb387c6b7d2f9.js",revision:"0cbeb387c6b7d2f9"},{url:"/_next/static/chunks/3762-1c91083fb1a622c0.js",revision:"1c91083fb1a622c0"},{url:"/_next/static/chunks/416.e8f04b8e9d246c5d.js",revision:"e8f04b8e9d246c5d"},{url:"/_next/static/chunks/4296-d8fbf75df3b777b4.js",revision:"d8fbf75df3b777b4"},{url:"/_next/static/chunks/4589-ddaaeca1ea084b22.js",revision:"ddaaeca1ea084b22"},{url:"/_next/static/chunks/4871.a78304faf25ea37e.js",revision:"a78304faf25ea37e"},{url:"/_next/static/chunks/4bd1b696-100b9d70ed4e49c1.js",revision:"100b9d70ed4e49c1"},{url:"/_next/static/chunks/5125-c990fc036d2a6ce4.js",revision:"c990fc036d2a6ce4"},{url:"/_next/static/chunks/5204-40bcee73ecd8ab8c.js",revision:"40bcee73ecd8ab8c"},{url:"/_next/static/chunks/5352-2d1b054130cf56bf.js",revision:"2d1b054130cf56bf"},{url:"/_next/static/chunks/5380-9004e1ac3565daca.js",revision:"9004e1ac3565daca"},{url:"/_next/static/chunks/5385-7ecda8e4ba984edc.js",revision:"7ecda8e4ba984edc"},{url:"/_next/static/chunks/5482-7535aa0aab02d518.js",revision:"7535aa0aab02d518"},{url:"/_next/static/chunks/5769-41ddcfc7762d7501.js",revision:"41ddcfc7762d7501"},{url:"/_next/static/chunks/5786-300f6f4e5c444b8e.js",revision:"300f6f4e5c444b8e"},{url:"/_next/static/chunks/5942.e3bd8fc7fc1e4596.js",revision:"e3bd8fc7fc1e4596"},{url:"/_next/static/chunks/6088-c165c565edce02be.js",revision:"c165c565edce02be"},{url:"/_next/static/chunks/6286-086a26f8f0ae31b4.js",revision:"086a26f8f0ae31b4"},{url:"/_next/static/chunks/6293-a9927cacf03898b6.js",revision:"a9927cacf03898b6"},{url:"/_next/static/chunks/670-a4ca0f366ee779f5.js",revision:"a4ca0f366ee779f5"},{url:"/_next/static/chunks/6847-ce99bc721adda9c4.js",revision:"ce99bc721adda9c4"},{url:"/_next/static/chunks/6873-ff265086321345c8.js",revision:"ff265086321345c8"},{url:"/_next/static/chunks/710-7e96cbf5d461482a.js",revision:"7e96cbf5d461482a"},{url:"/_next/static/chunks/7332-fd60cdf555c2ea53.js",revision:"fd60cdf555c2ea53"},{url:"/_next/static/chunks/7359-1abfb9f346309354.js",revision:"1abfb9f346309354"},{url:"/_next/static/chunks/7567-0776b78d8fa131c0.js",revision:"0776b78d8fa131c0"},{url:"/_next/static/chunks/7741-0af8b5a61d8e63d3.js",revision:"0af8b5a61d8e63d3"},{url:"/_next/static/chunks/7855-72c79224370eff7b.js",revision:"72c79224370eff7b"},{url:"/_next/static/chunks/787-032067ae978e62a8.js",revision:"032067ae978e62a8"},{url:"/_next/static/chunks/7917-630571e0a7d1019f.js",revision:"630571e0a7d1019f"},{url:"/_next/static/chunks/8241-eaf1b9c6054e9ad8.js",revision:"eaf1b9c6054e9ad8"},{url:"/_next/static/chunks/8286-7d0f4d46ecab678b.js",revision:"7d0f4d46ecab678b"},{url:"/_next/static/chunks/8466-ffa71cea7998f777.js",revision:"ffa71cea7998f777"},{url:"/_next/static/chunks/8721-4fdab69857d188e9.js",revision:"4fdab69857d188e9"},{url:"/_next/static/chunks/8746-92ff3ad56eb06d6e.js",revision:"92ff3ad56eb06d6e"},{url:"/_next/static/chunks/8930.1853f82129e20bef.js",revision:"1853f82129e20bef"},{url:"/_next/static/chunks/9205-f540995b767df00b.js",revision:"f540995b767df00b"},{url:"/_next/static/chunks/9397-40b8ac68e22a4d87.js",revision:"40b8ac68e22a4d87"},{url:"/_next/static/chunks/9811-2efcf2d216d2373b.js",revision:"2efcf2d216d2373b"},{url:"/_next/static/chunks/app/(auth)/forgot-password/page-468863a70b7f33bd.js",revision:"468863a70b7f33bd"},{url:"/_next/static/chunks/app/(auth)/login/page-c220f5f8f2ed10f6.js",revision:"c220f5f8f2ed10f6"},{url:"/_next/static/chunks/app/(auth)/onboarding/page-523c4adefb919140.js",revision:"523c4adefb919140"},{url:"/_next/static/chunks/app/(auth)/register/page-ab3799fa4df2090e.js",revision:"ab3799fa4df2090e"},{url:"/_next/static/chunks/app/(auth)/reset-password/page-b3351aa7bf1d737f.js",revision:"b3351aa7bf1d737f"},{url:"/_next/static/chunks/app/_not-found/page-95f11f5fe94340f1.js",revision:"95f11f5fe94340f1"},{url:"/_next/static/chunks/app/activities/page-4f906e4431600a36.js",revision:"4f906e4431600a36"},{url:"/_next/static/chunks/app/ai-assistant/page-31869b104c2893be.js",revision:"31869b104c2893be"},{url:"/_next/static/chunks/app/analytics/page-ab71bfe91aef0dfd.js",revision:"ab71bfe91aef0dfd"},{url:"/_next/static/chunks/app/api/ai/chat/route-a631d97a33877f8a.js",revision:"a631d97a33877f8a"},{url:"/_next/static/chunks/app/api/auth/login/route-a631d97a33877f8a.js",revision:"a631d97a33877f8a"},{url:"/_next/static/chunks/app/api/auth/password-reset/route-a631d97a33877f8a.js",revision:"a631d97a33877f8a"},{url:"/_next/static/chunks/app/api/auth/register/route-a631d97a33877f8a.js",revision:"a631d97a33877f8a"},{url:"/_next/static/chunks/app/api/health/route-a631d97a33877f8a.js",revision:"a631d97a33877f8a"},{url:"/_next/static/chunks/app/api/tracking/feeding/route-a631d97a33877f8a.js",revision:"a631d97a33877f8a"},{url:"/_next/static/chunks/app/api/voice/transcribe/route-a631d97a33877f8a.js",revision:"a631d97a33877f8a"},{url:"/_next/static/chunks/app/children/page-36ad2a3268ab26dc.js",revision:"36ad2a3268ab26dc"},{url:"/_next/static/chunks/app/family/page-2f110249fcfd1412.js",revision:"2f110249fcfd1412"},{url:"/_next/static/chunks/app/history/page-7cab5f74bb875f16.js",revision:"7cab5f74bb875f16"},{url:"/_next/static/chunks/app/insights/page-dd390b978f516172.js",revision:"dd390b978f516172"},{url:"/_next/static/chunks/app/layout-1c9d8110b20dfde0.js",revision:"1c9d8110b20dfde0"},{url:"/_next/static/chunks/app/logout/page-359b0e371fd55c32.js",revision:"359b0e371fd55c32"},{url:"/_next/static/chunks/app/offline/page-28c005360c2b2736.js",revision:"28c005360c2b2736"},{url:"/_next/static/chunks/app/page-b9e045df422df68b.js",revision:"b9e045df422df68b"},{url:"/_next/static/chunks/app/settings/page-550346811c93268f.js",revision:"550346811c93268f"},{url:"/_next/static/chunks/app/track/activity/page-075cf736b89c38e4.js",revision:"075cf736b89c38e4"},{url:"/_next/static/chunks/app/track/diaper/page-8bfd33a415e648a5.js",revision:"8bfd33a415e648a5"},{url:"/_next/static/chunks/app/track/feeding/page-94ea6af8da6d4df3.js",revision:"94ea6af8da6d4df3"},{url:"/_next/static/chunks/app/track/medicine/page-98485267d91dd81f.js",revision:"98485267d91dd81f"},{url:"/_next/static/chunks/app/track/page-df6b6a1084e8d8c5.js",revision:"df6b6a1084e8d8c5"},{url:"/_next/static/chunks/app/track/sleep/page-b14029bd2898d59c.js",revision:"b14029bd2898d59c"},{url:"/_next/static/chunks/framework-bd61ec64032c2de7.js",revision:"bd61ec64032c2de7"},{url:"/_next/static/chunks/main-520e5ec2d671abe7.js",revision:"520e5ec2d671abe7"},{url:"/_next/static/chunks/main-app-02fc3649960ba6c7.js",revision:"02fc3649960ba6c7"},{url:"/_next/static/chunks/pages/_app-4b3fb5e477a0267f.js",revision:"4b3fb5e477a0267f"},{url:"/_next/static/chunks/pages/_error-c970d8b55ace1b48.js",revision:"c970d8b55ace1b48"},{url:"/_next/static/chunks/polyfills-42372ed130431b0a.js",revision:"846118c33b2c0e922d7b3a7676f81f6f"},{url:"/_next/static/chunks/webpack-ad987399c7124b46.js",revision:"ad987399c7124b46"},{url:"/_next/static/css/0e32a1f7dc037ce2.css",revision:"0e32a1f7dc037ce2"},{url:"/_next/static/media/19cfc7226ec3afaa-s.woff2",revision:"9dda5cfc9a46f256d0e131bb535e46f8"},{url:"/_next/static/media/21350d82a1f187e9-s.woff2",revision:"4e2553027f1d60eff32898367dd4d541"},{url:"/_next/static/media/8e9860b6e62d6359-s.woff2",revision:"01ba6c2a184b8cba08b0d57167664d75"},{url:"/_next/static/media/ba9851c3c22cd980-s.woff2",revision:"9e494903d6b0ffec1a1e14d34427d44d"},{url:"/_next/static/media/c5fe6dc8356a8c31-s.woff2",revision:"027a89e9ab733a145db70f09b8a18b42"},{url:"/_next/static/media/df0a9ae256c0569c-s.woff2",revision:"d54db44de5ccb18886ece2fda72bdfe0"},{url:"/_next/static/media/e4af272ccee01ff0-s.p.woff2",revision:"65850a373e258f1c897a2b3d75eb74de"},{url:"/icons/icon-128x128.png",revision:"d41d8cd98f00b204e9800998ecf8427e"},{url:"/icons/icon-144x144.png",revision:"d41d8cd98f00b204e9800998ecf8427e"},{url:"/icons/icon-152x152.png",revision:"d41d8cd98f00b204e9800998ecf8427e"},{url:"/icons/icon-192x192.png",revision:"d41d8cd98f00b204e9800998ecf8427e"},{url:"/icons/icon-384x384.png",revision:"d41d8cd98f00b204e9800998ecf8427e"},{url:"/icons/icon-512x512.png",revision:"d41d8cd98f00b204e9800998ecf8427e"},{url:"/icons/icon-72x72.png",revision:"d41d8cd98f00b204e9800998ecf8427e"},{url:"/icons/icon-96x96.png",revision:"d41d8cd98f00b204e9800998ecf8427e"},{url:"/manifest.json",revision:"5be5ec81beca107e804b38758d51abd5"},{url:"/next.svg",revision:"8e061864f388b47f33a1c3780831193e"},{url:"/vercel.svg",revision:"61c6b19abff40ea7acd577be818f3976"}],{ignoreURLParametersMatching:[]}),e.cleanupOutdatedCaches(),e.registerRoute("/",new e.NetworkFirst({cacheName:"start-url",plugins:[{cacheWillUpdate:async({request:e,response:s,event:a,state:c})=>s&&"opaqueredirect"===s.type?new Response(s.body,{status:200,statusText:"OK",headers:s.headers}):s}]}),"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: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)$/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:32,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(/\/api\/.*$/i,new e.NetworkFirst({cacheName:"apis",networkTimeoutSeconds:10,plugins:[new e.ExpirationPlugin({maxEntries:16,maxAgeSeconds:86400})]}),"GET"),e.registerRoute(/.*/i,new e.NetworkFirst({cacheName:"others",networkTimeoutSeconds:10,plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400})]}),"GET")});