PageSourceSearch

https://entenc.com/assets/Settings-oFdxBs8_.js

js entenc.com collected 2026-10-02 01:28:23 UTC 9,942 bytes, 11 lines download raw bytes

1import{u as se,r as s,j as e}from"./react-DfPlzfW8.js";import{c as Y,u as ne,g as P,Z as ie,s as K,a as re,r as oe,A as le}from"./index-wN3cS0bk.js";import{B as c}from"./Button-Cdt5vxnR.js";import{C as y,P as z}from"./Pill-DDtYYaBX.js";import{I as F}from"./Input-T_VFESq-.js";import{S as I}from"./StatusMessage-Ce84NPfC.js";import{C as de}from"./circle-check-D6Lo10g1.js";import"./i18n-CaZbNrtY.js";import"./supabase-Dfky9hfI.js";/**
2 * @license lucide-react v0.546.0 - ISC
3 *
4 * This source code is licensed under the ISC license.
5 * See the LICENSE file in the root directory of this source tree.
6 */const ce=[["path",{d:"M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49",key:"ct8e1f"}],["path",{d:"M14.084 14.158a3 3 0 0 1-4.242-4.242",key:"151rxh"}],["path",{d:"M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143",key:"13bj9a"}],["path",{d:"m2 2 20 20",key:"1ooewy"}]],me=Y("eye-off",ce);/**
7 * @license lucide-react v0.546.0 - ISC
8 *
9 * This source code is licensed under the ISC license.
10 * See the LICENSE file in the root directory of this source tree.
11 */const ue=[["path",{d:"M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0",key:"1nclc0"}],["circle",{cx:"12",cy:"12",r:"3",key:"1v7zrd"}]],xe=Y("eye",ue),B=30,pe=B*24*60*60*1e3;async function U(n){const{data:m}=await K.from("user_profiles").select("display_name,display_name_updated_at,tier").eq("id",n).maybeSingle();return m||null}function Se(){const{user:n,session:m,isPro:g,signOut:q}=ne(),H=se(),[l,k]=s.useState(null),[M,O]=s.useState(!0),[L,T]=s.useState(""),[v,u]=s.useState(!1),[j,i]=s.useState(null),[r,b]=s.useState(null),[W,D]=s.useState(!0),[N,G]=s.useState(""),[S,Z]=s.useState(!1),[x,p]=s.useState(!1),[w,o]=s.useState(null),[J,$]=s.useState(!1),[_,f]=s.useState(null);s.useEffect(()=>{if(!n?.id)return;let t=!1;return(async()=>{O(!0);const a=await U(n.id);t||(k(a),T(a?.display_name||""),O(!1))})(),()=>{t=!0}},[n?.id]),s.useEffect(()=>{let t=!1;return(async()=>{D(!0);const a=await P();t||(b(a),D(!1))})(),()=>{t=!0}},[]);const d=s.useMemo(()=>{if(!l?.display_name_updated_at)return 0;const t=new Date(l.display_name_updated_at).getTime();return Number.isNaN(t)?0:Math.max(0,t+pe-Date.now())},[l?.display_name_updated_at]),C=s.useMemo(()=>{if(d<=0)return null;const t=Math.ceil(d/(1440*60*1e3));return`Available in ${t} day${t===1?"":"s"}`},[d]);async function V(){if(!n?.id)return;const t=L.trim();if(t.length<2||t.length>30){i({kind:"error",text:"Name must be 2–30 characters."});return}if((l?.display_name||"")===t){i({kind:"info",text:"No change to save."});return}if(d>0){i({kind:"error",text:`Name change on cooldown. ${C}.`});return}u(!0),i({kind:"info",text:"Checking availability…"});const{data:a,error:h}=await K.from("user_profiles").select("id").eq("display_name",t).neq("id",n.id).limit(1);if(h){u(!1),i({kind:"error",text:h.message||"Could not verify name availability."});return}if(a&&a.length>0){u(!1),i({kind:"error",text:"That name is already taken. Try another."});return}i({kind:"info",text:"Saving…"});const E=new Date().toISOString(),{error:A}=await K.from("user_profiles").update({display_name:t,display_name_updated_at:E,updated_at:E}).eq("id",n.id);if(u(!1),A){if(A.code==="23505"){i({kind:"error",text:"That name is already taken. Try another."});return}i({kind:"error",text:A.message||"Could not save name."});return}k(R=>({display_name:t,display_name_updated_at:E,tier:R?.tier??null})),i({kind:"success",text:"Display name updated."})}async function Q(){const t=N.trim();if(t.length<10){o({kind:"error",text:"Paste a valid Gemini API key."});return}p(!0),o({kind:"info",text:"Validating with Gemini…"});const a=await re(t);if(p(!1),a.status==="success"){o({kind:"success",text:"Key connected. AI translations enabled."}),G("");const h=await P();b(h)}else a.status==="not_installed"?o({kind:"error",text:"Install / reload the Entenc extension first."}):o({kind:"error",text:a.message})}async function X(){p(!0),o({kind:"info",text:"Removing…"});const t=await oe();if(p(!1),t.status==="success"){o({kind:"success",text:"Key removed. Tier reverted to Premium."});const a=await P();b(a),n?.id&&k(await U(n.id))}else o({kind:"error",text:t.message})}async function ee(){if(m){$(!0),f(null);try{const t=await fetch(`${le}/api/v1/checkout/portal`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${m.access_token}`},body:JSON.stringify({returnUrl:`${window.location.origin}
11/app/settings`})}),a=await t.json().catch(()=>({}));if(t.ok&&a.url){window.location.href=a.url;return}if(t.status===404){f({kind:"info",text:"No paid Stripe subscription on file, so there is nothing to manage here. If you have Premium access it was granted directly on your account rather than bought."});return}f({kind:"error",text:a.error||`Could not open billing portal (HTTP ${t.status}).`})}catch(t){console.error("Failed to open portal:",t),f({kind:"error",text:"Could not reach the billing portal. Try again."})}finally{$(!1)}}}async function te(){await q(),H("/")}const ae=(()=>{const t=l?.tier;return t==="admin"?"Admin":t==="premiumplus"?"Pro":t==="premium"?"Premium":"Free"})();return e.jsxs("div",{className:"max-w-[650px]",children:[e.jsxs("section",{className:"page-intro",children:[e.jsx("div",{className:"eyebrow",children:"MAKE YOURSELF AT HOME"}),e.jsx("h1",{children:"Your little corner."}),e.jsx("p",{children:"A few personal touches for your learning space."})]}),e.jsxs(y,{className:"mb-6",children:[e.jsx("div",{className:"eyebrow mb-4",children:"PROFILE"}),e.jsxs("div",{className:"flex items-center gap-4 mb-6",children:[n?.user_metadata?.avatar_url&&e.jsx("img",{src:n.user_metadata.avatar_url,alt:"",className:"w-12 h-12 rounded-full border border-line"}),e.jsxs("div",{children:[e.jsx("p",{className:"text-ink font-semibold text-[15px]",children:l?.display_name||n?.user_metadata?.full_name||n?.email}),e.jsx("p",{className:"text-ink-soft text-[12px]",children:n?.email}),e.jsxs("p",{className:"text-ink-soft text-[11px] mt-1",children:["Plan: ",ae]})]})]}),e.jsx("label",{className:"block text-xs font-semibold text-ink mb-2",children:"Display name"}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx(F,{type:"text",value:L,onChange:t=>T(t.target.value),maxLength:30,disabled:M||v||d>0,placeholder:"Your display name",className:"flex-1"}),e.jsx(c,{variant:"secondary",onClick:V,disabled:M||v||d>0,loading:v,children:"Save"})]}),C&&e.jsxs("p",{className:"text-ink-soft text-[11px] mt-2",children:["Name changes are limited to once per ",B," days. ",C,"."]}),j&&e.jsx("div",{className:"mt-2",children:e.jsx(I,{kind:j.kind,children:j.text})})]}),e.jsxs(y,{className:"mb-6",children:[e.jsx("div",{className:"eyebrow mb-4",children:"SUBSCRIPTION"}),e.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-3",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[g?e.jsxs(z,{tone:"accent",children:[e.jsx(ie,{size:12})," Premium"]}):e.jsx(z,{tone:"neutral",children:"Free"}),e.jsx("span",{className:"text-ink-soft text-[12px]",children:g?"Unlimited lookups · 500-card vault · full song catalog":"30 lookups a day · 10-card vault · weekly song rotation"})]}),g?e.jsx(c,{variant:"secondary",onClick:ee,loading:J,children:"Manage"}):e.jsx("a",{href:"/app/upgrade",children:e.jsx(c,{children:"Upgrade to Premium"})})]}),_&&e.jsx("div",{className:"mt-3",children:e.jsx(I,{kind:_.kind,children:_.text})})]}),e.jsxs(y,{className:"mb-6",children:[e.jsxs("div",{className:"flex items-baseline justify-between mb-4",children:[e.jsx("div",{className:"eyebrow",children:"GEMINI API KEY"}),r?.installed&&e.jsxs("span",{className:"text-[11px] text-ink-soft",children:["Extension v",r.version||"?"]})]}),e.jsx("p",{className:"text-ink-soft text-[12px] mb-4",children:"Paste your own Gemini key to unlock live AI subtitles and AI dictionary fills, on any plan. You pay Google directly for what you use; Entenc never bills for AI."}),W?e.jsx("p",{className:"notice",children:"Checking extension…"}):r?.installed?e.jsxs(e.Fragment,{children:[r.hasApiKey&&e.jsxs("p",{className:"text-[#5f6d2e] text-[12px] mb-3 flex items-center gap-1.5",children:[e.jsx(de,{size:14,className:"text-[#7e8b51]"}),"Key connected",r.maskedKey?` (${r.maskedKey})`:""," — AI translations enabled."]}),e.jsx("label",{className:"block text-xs font-semibold text-ink mb-2",children:r.hasApiKey?"Update key":"Paste your Gemini key"}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx(F,{type:S?"text":"password",value:N,onChange:t=>G(t.target.value),placeholder:"AIza…",disabled:x,className:"flex-1"}),e.jsx("button",{type:"button",onClick:()=>Z(t=>
11!t),className:"px-3 py-2 rounded-lg border border-line bg-card text-ink-soft text-sm hover:bg-lavender/60 hover:text-ink transition-colors","aria-label":S?"Hide key":"Show key",children:S?e.jsx(me,{size:16}):e.jsx(xe,{size:16})}),e.jsx(c,{variant:"secondary",onClick:Q,disabled:x||N.trim().length<10,loading:x,children:r.hasApiKey?"Update":"Connect"})]}),r.hasApiKey&&e.jsx(c,{variant:"danger",onClick:X,loading:x,className:"mt-3",children:"Remove key (reverts to Premium)"}),w&&e.jsx("div",{className:"mt-3",children:e.jsx(I,{kind:w.kind,children:w.text})}),e.jsxs("p",{className:"text-[11px] text-ink-soft mt-3",children:["Your key stays in the extension's local storage and is never sent to Entenc's servers. Get one free at"," ",e.jsx("a",{href:"https://aistudio.google.com/app/apikey",target:"_blank",rel:"noopener noreferrer",className:"underline hover:text-ink",children:"Google AI Studio"}),"."]})]}):e.jsx("p",{className:"notice warm",children:"The Entenc extension isn't reachable. Install or reload it, then refresh this page."})]}),e.jsxs(y,{children:[e.jsx("div",{className:"eyebrow mb-4",children:"SESSION"}),e.jsx(c,{variant:"danger",onClick:te,children:"Sign Out"})]})]})}export{Se 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.