PageSourceSearch

https://nguyentudo.me/assets/AdminOneOnOnePage--NJVBsq0.js

js nguyentudo.me collected 2026-10-04 14:32:16 UTC 8,178 bytes, 1 lines download raw bytes

1import{W as g,aJ as m,aK as _,s as c,r as p,j as e,I as N,h as u,ap as L,n as l,x as K,z as k,F as M,G as D}from"./index-CyZ-pQAp.js";import{T as H,a as Q,b as y,c as h,d as E,e as d}from"./table-CMi6u7Ia.js";import{C as B,b as z,c as R,a as P}from"./card-DrHtq4Bk.js";function I(){return g({queryKey:["one-on-one-slots"],queryFn:async()=>{const{data:o,error:t}=await c.from("one_on_one_slots").select("*, one_on_one_slot_registrations(registration_name, registration_phone, registration_goal)");if(t)throw t;return(o||[]).map(r=>{const s=Array.isArray(r.one_on_one_slot_registrations)?r.one_on_one_slot_registrations[0]:r.one_on_one_slot_registrations;return{...r,registration_name:(s==null?void 0:s.registration_name)??null,registration_phone:(s==null?void 0:s.registration_phone)??null,registration_goal:(s==null?void 0:s.registration_goal)??null}})}})}function U(){return g({queryKey:["one-on-one-settings"],queryFn:async()=>{const{data:o,error:t}=await c.from("one_on_one_settings").select("*").maybeSingle();if(t)throw t;return o}})}function V(o,t){c.functions.invoke("notify-one-on-one",{body:{slot_id:o,event:t}}).catch(()=>{})}function G(){const o=m();return _({mutationFn:async t=>{const{error:r}=await c.rpc("admin_release_one_on_one_slot",{_slot_id:t});if(r)throw r},onSuccess:()=>o.invalidateQueries({queryKey:["one-on-one-slots"]})})}function J(){const o=m();return _({mutationFn:async t=>{const{error:r}=await c.rpc("admin_approve_one_on_one_slot",{_slot_id:t});if(r)throw r;return t},onSuccess:()=>o.invalidateQueries({queryKey:["one-on-one-slots"]})})}function W(){const o=m();return _({mutationFn:async t=>{const{error:r}=await c.rpc("admin_reject_one_on_one_slot",{_slot_id:t});if(r)throw r},onSuccess:()=>o.invalidateQueries({queryKey:["one-on-one-slots"]})})}function Y(){const o=m();return _({mutationFn:async({slotId:t,recordingUrl:r})=>{const{error:s}=await c.rpc("admin_complete_one_on_one_slot",{_slot_id:t,_recording_url:r});if(s)throw s;return t},onSuccess:t=>{o.invalidateQueries({queryKey:["one-on-one-slots"]}),t&&V(t,"completed")}})}const X={available:"Còn trống",pending_approval:"Chờ duyệt",claimed:"Đã duyệt",scheduled:"Đã đặt lịch",completed:"Hoàn thành"};function ne(){const o=m(),{data:t=[],isLoading:r}=I(),{data:s}=U(),C=G(),f=Y(),O=J(),S=W(),[j,q]=p.useState(""),[i,x]=p.useState(null),{data:v}=g({queryKey:["admin-courses-min"],queryFn:async()=>{const{data:n}=await c.from("courses").select("id, title").order("title");return n||[]}}),{data:b}=g({queryKey:["one-on-one-holders",t.map(n=>n.claimed_by_user_id).filter(Boolean).join(",")],enabled:t.some(n=>n.claimed_by_user_id),queryFn:async()=>{const n=Array.from(new Set(t.map(F=>F.claimed_by_user_id).filter(Boolean)));if(n.length===0)return[];const{data:a}=await c.from("profiles").select("user_id, display_name, email").in("user_id",n);return a||[]}}),T=p.useMemo(()=>{const n=new Map;return(v||[]).forEach(a=>n.set(a.id,a.title)),n},[v]),A=p.useMemo(()=>{const n=new Map;return(b||[]).forEach(a=>n.set(a.user_id,a)),n},[b]),w=_({mutationFn:async()=>{const n=parseInt(j);if(!Number.isFinite(n)||n<0)throw new Error("invalid");const{error:a}=await c.from("one_on_one_settings").update({max_slots_per_user:n,updated_at:new Date().toISOString()}).eq("id",!0);if(a)throw a},onSuccess:()=>{l.success("Đã cập nhật giới hạn"),o.invalidateQueries({queryKey:["one-on-one-settings"]})},onError:()=>l.error("Lỗi lưu")});return e.jsxs("div",{className:"max-w-6xl mx-auto space-y-6",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"text-2xl font-bold",children:"Suất học 1-1"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:"Quản lý suá
1º¥t 1-1 trá»±c tiếp cho mỗi khóa học"})]}),e.jsxs(B,{children:[e.jsx(z,{children:e.jsx(R,{className:"text-base",children:"Cấu hình"})}),e.jsxs(P,{className:"flex items-end gap-3",children:[e.jsxs("div",{className:"space-y-1",children:[e.jsx("label",{className:"text-xs text-muted-foreground",children:"Số suất tối đa / thành viên"}),e.jsx(N,{type:"number",min:0,placeholder:String((s==null?void 0:s.max_slots_per_user)??3),value:j,onChange:n=>q(n.target.value),className:"w-40"})]}),e.jsx(u,{onClick:()=>w.mutate(),disabled:!j||w.isPending,children:"Lưu"}),e.jsxs("span",{className:"text-sm text-muted-foreground ml-2",children:["Hiện tại: ",e.jsx("b",{children:(s==null?void 0:s.max_slots_per_user)??3})]})]})]}),e.jsx("div",{className:"rounded-xl bg-card border border-border overflow-hidden",children:e.jsxs(H,{children:[e.jsx(Q,{children:e.jsxs(y,{children:[e.jsx(h,{children:"Khóa học"}),e.jsx(h,{children:"Trạng thái"}),e.jsx(h,{children:"Người giữ"}),e.jsx(h,{children:"Lịch hẹn"}),e.jsx(h,{children:"Recording"}),e.jsx(h,{className:"text-right",children:"Hành động"})]})}),e.jsxs(E,{children:[r&&e.jsx(y,{children:e.jsx(d,{colSpan:6,className:"text-center text-muted-foreground",children:"Đang tải..."})}),!r&&t.length===0&&e.jsx(y,{children:e.jsx(d,{colSpan:6,className:"text-center text-muted-foreground",children:"Chưa có suất nào"})}),t.map(n=>{const a=n.claimed_by_user_id?A.get(n.claimed_by_user_id):null;return e.jsxs(y,{children:[e.jsx(d,{className:"font-medium",children:T.get(n.course_id)||n.course_id.slice(0,8)}),e.jsx(d,{children:e.jsx(L,{variant:n.status==="available"?"outline":n.status==="pending_approval"?"secondary":n.status==="completed"?"default":"secondary",className:n.status==="pending_approval"?"bg-yellow-500/15 text-yellow-500 border-yellow-500/30":"",children:X[n.status]})}),e.jsx(d,{className:"text-sm",children:a?e.jsxs("div",{className:"space-y-0.5",children:[e.jsx("div",{className:"font-medium",children:n.registration_name||a.display_name}),e.jsx("div",{className:"text-xs text-muted-foreground",children:a.email}),n.registration_phone&&e.jsxs("div",{className:"text-xs",children:["📱 ",n.registration_phone]}),n.registration_goal&&e.jsxs("div",{className:"text-xs text-muted-foreground italic line-clamp-2 max-w-[260px]",children:['"',n.registration_goal,'"']})]}):e.jsx("span",{className:"text-muted-foreground",children:"—"})}),e.jsx(d,{className:"text-sm",children:n.scheduled_at?new Date(n.scheduled_at).toLocaleString("vi-VN"):e.jsx("span",{className:"text-muted-foreground",children:"—"})}),e.jsx(d,{className:"text-xs max-w-[180px] truncate",children:n.recording_url?e.jsx("a",{href:n.recording_url,target:"_blank",rel:"noreferrer",className:"text-primary underline",children:n.recording_url}):e.jsx("span",{className:"text-muted-foreground",children:"—"})}),e.jsxs(d,{className:"text-right space-x-2 whitespace-nowrap",children:[n.status==="pending_approval"&&e.jsxs(e.Fragment,{children:[e.jsx(u,{size:"sm",variant:"cta",onClick:async()=>{try{await O.mutateAsync(n.id),l.success("Đã duyệt suất 1-1")}catch{l.error("Lỗi")}},children:"Duyệt"}),e.jsx(u,{size:"sm",variant:"outline",onClick:async()=>{if(confirm("Từ chối yêu cầu này?"))try{await S.mutateAsync(n.id),l.success("Đã từ chối")}catch{l.error("Lỗi")}},children:"Từ chối"})]}),n.status!=="available"&&n.status!=="pending_approval"&&e.jsx(u,{variant:"outline",size:"sm",onClick:async()=>{if(confirm("Trả lại suất này?"))try{await C.mutateAsync(n.id),l.success("Đã trả lại suất")}catch{l.error("Lỗi")}},children:"Trả lại"}),n.status!=="available"&&n.status!=="pending_approval"&&e.jsx(u,{size:"sm",onClick:()=>x({id:n.id,url:n.recording_url||""}),children:"Hoàn thành"})]})]},n.id)})]})]})}),e.jsx(K,{open:!!i,onOpenChange:n=>!n&&x(null),children:e.jsxs(k,{children:[e.jsx(M,{children:e.jsx(D,{children:"Đánh dấu hoàn thành + dán link video"})}),e.jsxs("div",{className:"space-y-3",children:[e.jsx(N,{placeholder:"https://... (YouTube, Vimeo, Drive)",value:(i==null?void 0:i.url)||"",onChange:n=>x(a=>a&&{...a,url:n.target.value})}),e.jsx(u,{className:"w-full",disabled:!(i!=null&&i.url)||f.isPending,onClick:async()=>
1{if(i)try{await f.mutateAsync({slotId:i.id,recordingUrl:i.url}),l.success("Đã hoàn thành và xuất bản video"),x(null)}catch{l.error("Lỗi")}},children:"Lưu & hiển thị video cho tất cả thành viên"})]})]})})]})}export{ne 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.