1import{r as e,j as t}from"./vendor-react-C9yDzYQD.js";import{supabase as s}from"./supabase-client-_h80EYw_.js";import{getOfflineMemoryCount as a,getOfflineBoardIds as o,getOfflineStorageUsed as r,getSyncState as n,getSyncQueueCount as i,clearOfflineData as l,saveOfflineBoard as d,replaceOfflineBoardMemories as c,saveOfflineMemories as m,getOfflineMemoriesByIds as u,getOfflineMemoryIds as h,deleteOfflineMemories as f,deleteOfflineMediaNotIn as x,setSyncState as p,saveOfflineBoards as w,saveOfflineMedia as g,getOfflineSetting as y,saveOfflineSetting as j}from"./offline-C2kw-B3Y.js";import{u as b}from"./useAuth-Dz3EPsxs.js";import{r as N}from"./boundedAsyncPool-BG_N2Lbq.js";import{a as v}from"./startup-platform-OWIpYyjW.js";import{u as S}from"./useOfflineQueue-BjhmMc_k.js";import{B as C}from"./button-CcIRk75H.js";import{P as M}from"./progress-BBCJsBYL.js";import{PageHeader as k}from"./PageHeader-Dt7JKE_V.js";import{S as _}from"./switch-CM-712rT.js";import{S as B}from"./settings-2-BlPhDt3l.js";import{I as E}from"./info-Cn1cLZ-U.js";import{C as U}from"./check-MQhLD6FV.js";import{C as D}from"./cloud-C6Bmhi7u.js";import{R as A}from"./refresh-cw-Bjlnjg0v.js";import{C as T}from"./cloud-off-ECsf_F2q.js";import{D as z}from"./download-CzaTzqTz.js";import{T as F}from"./triangle-alert-FKyvs90R.js";import{D as O}from"./database-JSGDloae.js";import{T as $}from"./trash-2-B7zVZuh_.js";import{W as q}from"./wifi-off-DgTu9GsA.js";const P=()=>new Promise(e=>setTimeout(e,0)),L=async(e,t,s=200)=>{const a=Math.max(1,Math.floor(s));let o=0,r=null;for(;;){const s=await e(o,o+a-1);if(s.error)throw s.error;const n=s.data||[];if("number"==typeof s.count&&(r=s.count),0===n.length)break;const i=o+n.length;if(await t(n,{processedBefore:o,processedAfter:i,totalCount:r}),o=i,n.length<a||null!==r&&o>=r)break;await P()}return{processed:o,totalCount:r}},R=e=>{var t;try{null==(t=e.body)||t.cancel().catch(()=>{})}catch{}},W=v()?2:4,Y=200,I=e=>[e.image_url,e.video_url,e.source_url].filter((e,t,s)=>"string"==typeof e&&e.length>0&&s.indexOf(e)===t),J=e=>{let t=-1,s=0;return(a,o)=>{const r=o>0?Math.round(a/o*100):100,n=Date.now();r!==t&&(r<100&&n-s<100||(t=r,s=n,e(r)))}},Q=()=>{const{isDownloading:P,offlineStats:Q,downloadEverything:G,downloadNewContent:H,clearOffline:K,refreshStats:X,estimateTotalSize:V}=function(){const[t,y]=e.useState(0),[j,S]=e.useState(0),[C,M]=e.useState(!1),[k,_]=e.useState(null),[B,E]=e.useState({totalMemories:0,downloadedMemories:0,totalBoards:0,downloadedBoards:0,newMemoriesCount:0,pendingSyncCount:0,lastSyncTimestamp:null,storageUsed:0}),{toast:U}=b(),D=async e=>{if(!e)return;const t=v();await(async(e,t)=>{const s=new AbortController;let a=!1;const o=setTimeout(()=>{a=!0,s.abort()},t.timeoutMs);try{const a=await(t.fetchImpl||fetch)(e,{signal:s.signal});if(!a.ok||206===a.status)return R(a),"http-error";const o=Number(a.headers.get("content-length"));if(Number.isFinite(o)&&o>t.maxBytes)return R(a),"too-large";const r=o>0?await a.blob():await(async(e,t)=>{if(!e.body){const s=await e.blob();return s.size<=t?s:null}const s=e.body.getReader(),a=[];let o=0;try{for(;;){const{done:e,value:r}=await s.read();if(e)break;if(r){if(o+=r.byteLength,o>t)return await s.cancel(),null;a.push(r)}}}finally{s.releaseLock()}const r=new Uint8Array(o);let n=0;for(const i of a)r.set(i,n),n+=i.byteLength;return new Blob([r.buffer],{type:e.headers.get("content-type")||""})})(a,t.maxBytes);return!r||r.size>t.maxBytes?"too-large":o>0&&r.size!==o?"failed":(await t.save(e,r),"saved")}catch(r){return a||r instanceof DOMException&&"AbortError"===r.name?"timed-out":"failed"}finally{clearTimeout(o)}})(e,{maxBytes:t?50331648:134217728,timeoutMs:t?45e3:9e4,save:g})},A=e.useCallback(async()=>{try{const{data:{user:e}}=await s.auth.getUser();if(!e)return;const[t,l,d,c,m,u,h]=await Promise.all([s.from("memories").select("id",{count:"planned",head:!0}).eq("user_id",e.id).is("deleted_at",null),s.from("boards").select("id",{count:"planned",head:!0}).eq("user_id",e.id),a(),o(),r(),n("memories"),i()]),f=t.count||0,x=l.count||0,p=h,w=Math.min(d,f),g=Math.max(0,f-w);E({totalMemories:f,downloadedMemories:w,totalBoards:x,downloadedBoards:c.size,newMemoriesCount:g,pendingSyncCount:p,lastSyncTimestamp:(null==u?void 0:u.lastSyncTimestamp)||null,storageUsed:m})}catch(e){}},[]);e.useEffect(()=>{A()},[A]);const T=e.useCallback(async()=>{const{data:{user:e}}=await s.auth.getUser();if(!e)return 0;const{count:t}=await s.from("memories").select("id",{count:"planned",head:!0}).eq("user_id",e.id).is("deleted_at",null);return 209920*(t||0)},[]),z=e.useCallback(async e=>{const{count:t}=await s.from("memory_boards").select("id",{count:"exact",head:!0}).eq("board_id",e);return 209920*(t||0)},[]),F=e.useCallback(async()=>{await l(),await A(),U({title:"Offline Cache Cleared"})},[U,A]);return{downloadProgress:t,boardProgress:j,isDownloading:C,currentBoardDownloading:k,offlineStats:B,downloadEverything:async()=>
1{if(!C){M(!0),y(0);try{const{data:{user:e}}=await s.auth.getUser();if(!e)throw new Error("Not authenticated");const t=[];await L((t,a)=>s.from("boards").select("*",{count:"exact"}).eq("user_id",e.id).order("id").range(t,a),async e=>{t.push(...e),await w(e)},Y);const a=new Set,o=new Set,r=J(y),n=(await L((t,a)=>s.from("memories").select("*",{count:"exact"}).eq("user_id",e.id).is("deleted_at",null).order("id").range(t,a),async(e,t)=>{e.forEach(e=>a.add(e.id)),await m(e);const s=t.totalCount||t.processedAfter;await N(e,W,async e=>{const t=I(e);t.forEach(e=>o.add(e));for(const s of t)await D(s)},e=>{r(t.processedBefore+e,s)})},Y)).processed;await x(o);const i=t.map(e=>e.id);if(i.length>0){const e=new Map;i.forEach(t=>e.set(t,[]));for(let t=0;t<i.length;t+=Y){const a=i.slice(t,t+Y);await L((e,t)=>s.from("memory_boards").select("board_id, memory_id",{count:"exact"}).in("board_id",a).order("id").range(e,t),async t=>{t.forEach(t=>{var s;null==(s=e.get(t.board_id))||s.push(t.memory_id)})},Y)}await N(i,4,t=>c(t,e.get(t)||[]))}const l=[...await h()].filter(e=>!a.has(e));l.length>0&&await f(l),await p("memories",n),await A(),U(0===n?{title:"No echoes to download"}:{title:"Offline Sync Complete",description:`Saved ${n} echoes and ${t.length} boards.`})}catch(e){U({title:"Sync Failed",variant:"error"})}finally{M(!1),y(100)}}},downloadNewContent:async()=>{if(!C){M(!0),y(0);try{const{data:{user:e}}=await s.auth.getUser();if(!e)throw new Error("Not authenticated");const t=new Set,a=new Set;let o=0;const r=J(y),n=await L((t,a)=>s.from("memories").select("*",{count:"exact"}).eq("user_id",e.id).is("deleted_at",null).order("id").range(t,a),async(e,s)=>{e.forEach(e=>{t.add(e.id),I(e).forEach(e=>a.add(e))});const n=await u(e.map(e=>e.id)),i=e.filter(e=>{const t=n.get(e.id);return!t||t.updated_at!==e.updated_at||I(t).join("\n")!==I(e).join("\n")}),l=s.totalCount||s.processedAfter;await m(e),i.length>0&&(await N(i,W,async e=>{for(const t of I(e))await D(t)},(t,a)=>{const o=t/a,n=s.processedBefore+Math.round(e.length*o);r(n,l)}),o+=i.length),r(s.processedAfter,l)},Y),i=[...await h()].filter(e=>!t.has(e));if(i.length>0&&await f(i),await x(a),0===o&&0===i.length)return await A(),M(!1),void U({title:"All caught up!",description:"No new echoes to download."});await p("memories",n.processed),await A(),U({title:"Sync Complete",description:`Updated ${o} echoes${i.length?` and removed ${i.length}`:""}.`})}catch(e){U({title:"Sync Failed",variant:"error"})}finally{M(!1),y(100)}}},downloadBoard:async e=>{_(e),S(0);try{const{data:t,error:a}=await s.from("boards").select("*").eq("id",e).single();if(a)throw a;if(!t)return U({title:"Board not found"}),_(null),!1;await d(t);const o=[];if(await L((t,a)=>s.from("memory_boards").select("memory_id",{count:"exact"}).eq("board_id",e).order("id").range(t,a),async e=>{const t=e.map(e=>e.memory_id);o.push(...t)},Y),await c(e,o),0===o.length)return await A(),U({title:"Board saved",description:"This board has no echoes yet."}),_(null),!0;let r=0;const n=J(S);for(let e=0;e<o.length;e+=Y){const t=o.slice(e,e+Y),{data:a,error:i}=await s.from("memories").select("*").in("id",t).is("deleted_at",null);if(i)throw i;const l=a||[];await m(l),await N(l,W,async e=>{for(const t of I(e))await D(t)},t=>{n(e+t,o.length)}),r+=l.length}return await A(),U({title:"Board Downloaded",description:`Saved ${r} echoes offline.`}),!0}catch(t){return U({title:"Download Failed",variant:"error"}),!1}finally{_(null),S(100)}},clearOffline:F,refreshStats:A,estimateTotalSize:T,estimateBoardSize:z}}(),{syncQueue:Z,isSyncing:ee,attentionCount:te,retryNow:se}=S(X),{toast:ae}=b(),[oe,re]=e.useState(0),[ne,ie]=e.useState(!1);e.useEffect(()=>{y("autoUpload",!1).then(ie)},[]);const le=e=>{if(0===e)return"0 B";const t=Math.floor(Math.log(e)/Math.log(1024));return parseFloat((e/Math.pow(1024,t)).toFixed(2))+" "+["B","KB","MB","GB"][t]};e.useEffect(()=>{V().then(re)},[V]);const de=Q.totalMemories>0?Math.round(Q.downloadedMemories/Q.totalMemories*100):0,ce=0===Q.newMemoriesCount&&Q.downloadedMemories>0;return t.jsxs(t.Fragment,{children:[t.jsx("div",{className:"pointer-events-none fixed top-0 left-0 right-0 z-50",children:t.jsx(k,{title:"Offline",description:"Manage your offline content",className:"pointer-events-auto"})}),t.jsx("div",{className:"min-h-[100dvh] px-4 pb-[calc(8rem+env(safe-area-inset-bottom))] pt-[calc(6rem+env(safe-area-inset-top))] sm:px-6",children:t.jsxs("div",{className:"max-w-2xl mx-auto
1space-y-8",children:[t.jsxs("div",{className:"space-y-2",children:[t.jsx("h1",{className:"text-3xl font-bold tracking-tight",children:"Offline Mode"}),t.jsx("p",{className:"text-muted-foreground",children:"Download your echoes and boards to use Echo without an internet connection."})]}),t.jsxs("div",{className:"glass p-6 rounded-[2rem] space-y-6",children:[t.jsx("div",{className:"flex items-center justify-between",children:t.jsxs("div",{className:"flex items-center gap-3",children:[t.jsx("div",{className:"p-3 rounded-2xl bg-blue-500/10 text-blue-500",children:t.jsx(B,{className:"w-6 h-6"})}),t.jsxs("div",{children:[t.jsx("p",{className:"text-sm font-bold uppercase tracking-widest text-muted-foreground/60",children:"Sync Settings"}),t.jsx("p",{className:"text-xl font-bold",children:"Upload Control"})]})]})}),t.jsxs("div",{className:"flex items-center justify-between p-4 rounded-xl bg-muted/30 border border-white/5",children:[t.jsxs("div",{className:"space-y-0.5",children:[t.jsx("p",{className:"text-sm font-bold",children:"Automatic Uploads"}),t.jsx("p",{className:"text-xs text-muted-foreground",children:"Upload new echoes automatically when online"})]}),t.jsx(_,{checked:ne,onCheckedChange:async e=>{await j("autoUpload",e),ie(e),ae({title:e?"Automatic Uploads Enabled":"Automatic Uploads Disabled",description:e?"Your echoes will now upload automatically when you are online.":"New echoes will be saved locally until you manually sync them."})}})]}),!ne&&t.jsxs("p",{className:"text-xs text-amber-500 flex items-center gap-1.5 px-1 font-medium",children:[t.jsx(E,{className:"w-3.5 h-3.5"}),"New echoes will stay on your device until you manually sync them."]})]}),t.jsxs("div",{className:"glass p-6 rounded-[2rem] space-y-6",children:[t.jsxs("div",{className:"flex items-center justify-between",children:[t.jsxs("div",{className:"flex items-center gap-3",children:[t.jsx("div",{className:"p-3 rounded-2xl "+(ce?"bg-green-500/10 text-green-500":"bg-primary/10 text-primary"),children:ce?t.jsx(U,{className:"w-6 h-6"}):t.jsx(D,{className:"w-6 h-6"})}),t.jsxs("div",{children:[t.jsx("p",{className:"text-sm font-bold uppercase tracking-widest text-muted-foreground/60",children:ce?"All Synced":"Sync Status"}),t.jsxs("p",{className:"text-2xl font-black",children:[Q.downloadedMemories," ",t.jsxs("span",{className:"text-base font-normal text-muted-foreground",children:["of ",Q.totalMemories," echoes downloaded"]})]})]})]}),t.jsx(C,{variant:"ghost",size:"icon",className:"text-muted-foreground hover:text-foreground rounded-xl",onClick:X,disabled:P,children:t.jsx(A,{className:"w-5 h-5"})})]}),Q.totalMemories>0&&t.jsxs("div",{className:"space-y-2",children:[t.jsx(M,{value:de,className:"h-2"}),t.jsxs("div",{className:"flex justify-between text-xs text-muted-foreground",children:[t.jsxs("span",{children:[de,"% downloaded"]}),t.jsxs("span",{children:["Last sync: ",(e=>{if(!e)return"Never";const t=new Date(e),s=(new Date).getTime()-t.getTime(),a=Math.floor(s/6e4),o=Math.floor(s/36e5),r=Math.floor(s/864e5);return a<1?"Just now":a<60?`${a}m ago`:o<24?`${o}h ago`:`${r}d ago`})(Q.lastSyncTimestamp)]})]})]}),Q.newMemoriesCount>0&&t.jsxs("div",{className:"flex items-center gap-3 p-4 rounded-xl bg-primary/5 border border-primary/20",children:[t.jsx(T,{className:"w-5 h-5 text-primary shrink-0"}),t.jsxs("div",{className:"flex-1",children:[t.jsxs("p",{className:"text-sm font-bold",children:[Q.newMemoriesCount," new echoes not downloaded"]}),t.jsx("p",{className:"text-xs text-muted-foreground",children:"Download them to access offline"})]}),t.jsxs(C,{size:"sm",className:"rounded-xl shrink-0",onClick:H,disabled:P,children:[t.jsx(z,{className:"w-4 h-4 mr-1"}),"Sync New"]})]}),te>0&&t.jsxs("div",{role:"alert",className:"flex flex-col gap-3 rounded-xl border border-amber-500/30 bg-amber-500/10 p-4 sm:flex-row sm:items-center",children:[t.jsx(F,{className:"h-5 w-5 shrink-0 text-amber-600 dark:text-amber-400","aria-hidden":"true"}),t.jsxs("div",{className:"min-w-0 flex-1",children:[t.jsxs("p",{className:"text-sm font-bold",children:[te," ",1===te?"echo needs":"echoes need"," attention"]}),t.jsxs("p",{className:"text-xs text-muted-foreground",children:["Your ",1===te?"echo is":"echoes are"," still saved on this device. Retry when your connection is stable."]})]}),t.jsxs(C,{type:"button",size:"sm",className:"min-h-11 shrink-0 rounded-xl",onClick:()=>{se()},disabled:ee||!navigator.onLine,children:[t.jsx(A,{className:"mr-1.5 h-4 w-4 "+(ee?"animate-spin motion-reduce:animate-none":""),"aria-hidden":"true"}),"Retry Now"]})]}),Q.pendingSyncCount>0&&t.jsxs("div",{className:"flex items-center gap-3 p-4 rounded-xl bg-blue-500/5 border border-blue-500/20",children:[t.jsx(D,{className:"w-5 h-5 text-blue-500 shrink-0"}),t.jsxs("div",{className:"flex-1",children:[t.jsxs("p",{className:"text-sm font-bold",children:[Q.pendingSyncCount," echoes waiting to sync"]}),t.jsx("p",{className:"text-xs text-muted-foreground",children:"They remain saved on this device until upload succeeds"})]}),t.jsxs(C,{size:"sm",className:"rounded-xl shrink-0 gap-1.5",onClick:()=>{Z()},disabled:ee||!navigator.onLine,children:[ee?t.jsx(A,{className:"w-4 h-4 animate-spin"}):t.jsx(D,{className:"w-4 h-4"}),"Sync Now"]})]}),t.jsxs("div",{className:"pt-2 space-y-2",children:[t.jsx(C,{className:"w-full h-14 roun
1ded-2xl font-bold text-lg gap-2 shadow-lg shadow-primary/20",onClick:G,disabled:P,children:P?t.jsxs(t.Fragment,{children:[t.jsx("div",{className:"w-5 h-5 border-2 border-white/30 border-t-white rounded-full animate-spin"}),"Downloading..."]}):ce?t.jsxs(t.Fragment,{children:[t.jsx(U,{className:"w-5 h-5"}),"Re-sync Everything"]}):t.jsxs(t.Fragment,{children:[t.jsx(z,{className:"w-5 h-5"}),"Download Everything"]})}),oe>0&&!P&&t.jsxs("p",{className:"text-center text-xs text-muted-foreground",children:["Estimated size: ~",le(oe)]})]})]}),t.jsx("div",{className:"glass p-6 rounded-[2rem]",children:t.jsxs("div",{className:"flex items-center justify-between",children:[t.jsxs("div",{className:"flex items-center gap-3",children:[t.jsx("div",{className:"p-3 rounded-2xl bg-blue-500/10 text-blue-500",children:t.jsx(O,{className:"w-6 h-6"})}),t.jsxs("div",{children:[t.jsx("p",{className:"text-sm font-bold uppercase tracking-widest text-muted-foreground/60",children:"Local Storage"}),t.jsx("p",{className:"text-2xl font-black",children:le(Q.storageUsed)})]})]}),t.jsx(C,{variant:"ghost",size:"icon",className:"text-destructive hover:bg-destructive/10 rounded-xl",onClick:K,disabled:P||0===Q.storageUsed,children:t.jsx($,{className:"w-5 h-5"})})]})}),t.jsxs("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-4",children:[t.jsxs("div",{className:"glass p-6 rounded-[2rem] flex flex-col gap-3",children:[t.jsx("div",{className:"p-2 w-fit rounded-lg bg-primary/10 text-primary",children:t.jsx(q,{className:"w-5 h-5"})}),t.jsx("h3",{className:"font-bold",children:"Offline Access"}),t.jsx("p",{className:"text-xs text-muted-foreground leading-relaxed",children:"When offline, Echo will automatically use your local database to show your echoes and boards."})]}),t.jsxs("div",{className:"glass p-6 rounded-[2rem] flex flex-col gap-3",children:[t.jsx("div",{className:"p-2 w-fit rounded-lg bg-blue-500/10 text-blue-500",children:t.jsx(E,{className:"w-5 h-5"})}),t.jsx("h3",{className:"font-bold",children:"Automatic Updates"}),t.jsx("p",{className:"text-xs text-muted-foreground leading-relaxed",children:'New echoes you add aren\'t downloaded automatically. Use "Sync New" to grab the latest.'})]})]}),t.jsx("div",{className:"text-center pt-8",children:t.jsx("p",{className:"text-[10px] font-bold uppercase tracking-[0.2em] text-muted-foreground/40",children:"Your Data is Stored Safely on this Device"})})]})})]})};export{Q as default};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.