PageSourceSearch

https://delphigrc.org/assets/AdminEducation-CP39xC00.js

js delphigrc.org collected 2026-10-04 00:27:29 UTC 15,665 bytes, 1 lines download raw bytes

1import{r as e,j as t}from"./vendor-react-BH6F5oQJ.js";import{s,f as i,a0 as a,w as n,H as l,C as r,G as c,t as o}from"./index-dRqPaCFl.js";import{T as d}from"./textarea-DyrIuoRK.js";import{L as u}from"./label-RVODh2pd.js";import{b as p,e as m,T as h,a as x,c as g,d as j}from"./table-C7ziGuLk.js";import{D as f,f as v,a as y,b as _,c as b}from"./dialog-5O1RHm7r.js";import{S as N,a as C,b as w,c as k,d as A}from"./select-DsVkFSYt.js";import{S}from"./switch-B03ktsOR.js";import{A as D}from"./AdminLayout-CKCESQT6.js";import{L as T}from"./LazyRichTextEditor-ByQjI7gT.js";import{u as E,a as F}from"./vendor-query-CC4VRGyP.js";import{E as z,ab as L,Z as I,s as $,aa as M}from"./vendor-icons-CaI5__By.js";import{c as V}from"./validations-CCZ89lfg.js";import{u as q}from"./useActivityLogger-D_WtAITb.js";import{u as O}from"./useAdminActivityNotifications-B8Iov43A.js";import"./vendor-ui-B4WC06Sp.js";import"./vendor-supabase-COwyE4EW.js";import"./index-CCdGLatk.js";import"./Combination-DzDAyqvK.js";import"./index-B3FPD4RS.js";import"./separator-KtQ1mSuG.js";import"./en-US-DUAJ-5Wt.js";import"./slug-D4LuRHo0.js";import"./types-BnfuoFvn.js";async function P(e){const{data:t,error:i}=await s.from("courses").select("*").eq("id",e).maybeSingle();if(i)throw i;return t}function U(t){const i=t.pageSize??25,a=E(),{data:n,isLoading:l,isFetching:r,isError:c,error:o,refetch:d}=F({queryKey:["admin-courses-list",t.page,i,t.search],queryFn:()=>async function({page:e,pageSize:t,search:i}){const a=(e-1)*t,n=a+t-1;let l=s.from("courses").select("id,title,slug,subtitle,application_status,youtube_link,is_active,display_order,created_at,updated_at",{count:"exact"}).order("display_order",{ascending:!0}).range(a,n);const r=i.trim();if(r){const e=`%${c=r,c.replace(/[%_\\,]/g,e=>`\\${e}`)}%`;l=l.or(`title.ilike.${e},slug.ilike.${e},subtitle.ilike.${e}`)}var c;const{data:o,error:d,count:u}=await l;if(d)throw d;return{courses:o??[],totalCount:u??0}}({page:t.page,pageSize:i,search:t.search}),placeholderData:e=>e,staleTime:3e4}),u=(null==n?void 0:n.courses)??[],p=(null==n?void 0:n.totalCount)??0,m=e.useCallback(()=>{a.invalidateQueries({queryKey:["admin-courses-list"]})},[a]);return e.useEffect(()=>{const e=s.channel("admin-courses-changes").on("postgres_changes",{event:"*",schema:"public",table:"courses"},()=>m()).subscribe();return()=>{s.removeChannel(e)}},[m]),{courses:u,totalCount:p,pageSize:i,loading:l,isFetching:r,isError:c,error:o,refetch:d,invalidateList:m,fetchCourseById:P}}function B(e){return"accepting"===e?"Accepting":"closed"===e?"Closed":"Not Accepting"}const R=e.memo(function({course:e,onEdit:s,onDelete:a,onToggleActive:n,isTogglingActive:l=!1}){return t.jsxs(p,{children:[t.jsx(m,{className:"font-medium",children:e.title}),t.jsx(m,{children:e.slug}),t.jsx(m,{children:t.jsx("span",{className:"inline-flex items-center rounded-full px-2 py-1 text-xs font-medium "+(r=e.application_status,"accepting"===r?"bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-400":"closed"===r?"bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-400":"bg-yellow-100 text-yellow-800 dark:bg-yellow-900/30 dark:text-yellow-400"),children:B(e.application_status)})}),t.jsx(m,{children:t.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[t.jsx("span",{className:"inline-flex items-center rounded-full px-2 py-1 text-xs font-medium "+(e.is_active?"bg-blue-100 text-blue-800 dark:bg-blue-900/30 dark:text-blue-400":"bg-muted text-muted-foreground"),children:e.is_active?"Active":"Inactive"}),t.jsx(S,{checked:e.is_active,disabled:l,onCheckedChange:t=>n(e,t),"aria-label":e.is_active?"Deactivate course":"Activate course"})]})}),t.jsx(m,{children:e.display_order}),t.jsx(m,{className:"text-right",children:t.jsxs("div",{className:"flex justify-end gap-2",children:[e.youtube_link&&t.jsx(i,{variant:"ghost",size:"icon",onClick:()=>window.open(e.youtube_link,"_blank","noopener,noreferrer"),title:"Open YouTube",children:t.jsx(z,{className:"h-4 w-4"})}),t.jsx(i,{variant:"ghost",size:"icon",onClick:()=>s(e),title:"Edit",children:t.jsx(L,{className:"h-4 w-4"})}),t.jsx(i,{variant:"ghost",size:"icon",onClick:()=>a(e),title:"Delete",children:t.jsx(I,{className:"h-4 w-4"})})]})})]});var r}),G=()=>{const{addCourse:s,updateCourse:E,deleteCourse:F}=a({fetchList:!1}),{toast:z}=n(),{logActivity:L}=q();O();const[I,P]=e.useState(1),[B,G]=e.useState(""),K=e.useDeferredValue(B),[Q,Y]=e.useState(!1),[H,W]=e.useState(null),[X,Z]=e.useState(null),[J,ee]=e.useState(null),[te,se]=e.useState(!1),[ie,ae]=e.useState(null);e.useEffect(()=>{P(1)},[K]);const{courses:ne,totalCount:le,pageSize:re,loading:ce,isFetching:oe,fetchCourseById:de}=U({page:I,pageSize:25,search:K}),ue=Math.max(1,Math.ceil(le/re)),pe=0===le?0:(I-1)*re+1,me=Math.min(I*re,le),[he,xe]=e.useState({title:"",slug:"",subtitle:"",description:"",partner_info:"",certificate_info:"",objectives:"",sc
1hedule_info:"",application_status:"not_accepting",application_info:"",youtube_link:"",is_active:!0,display_order:0}),ge=()=>{xe({title:"",slug:"",subtitle:"",description:"",partner_info:"",certificate_info:"",objectives:"",schedule_info:"",application_status:"not_accepting",application_info:"",youtube_link:"",is_active:!0,display_order:0}),W(null),Z(null)},je=e.useCallback(e=>{W(e),Z(e),xe({title:e.title,slug:e.slug,subtitle:e.subtitle||"",description:e.description,partner_info:e.partner_info||"",certificate_info:e.certificate_info||"",objectives:Array.isArray(e.objectives)?e.objectives.join("\n"):"",schedule_info:e.schedule_info||"",application_status:e.application_status,application_info:e.application_info||"",youtube_link:e.youtube_link||"",is_active:e.is_active,display_order:e.display_order})},[]),fe=e.useCallback(async e=>{Y(!0),se(!0);try{const t=await de(e.id);if(!t)return z({title:"Error",description:"Course not found",variant:"destructive"}),void Y(!1);je(t)}catch{z({title:"Error",description:"Failed to load course",variant:"destructive"}),Y(!1)}finally{se(!1)}},[je,de,z]),ve=e.useCallback(e=>{ee(e)},[]),ye=e.useCallback(async()=>{if(!J)return;const{id:e,title:t,slug:s,is_active:i}=J;F.mutate(e),await L({activityType:"course_delete",entityType:"course",entityId:e,entityName:t,actionDescription:`Deleted course: ${t}`,oldValues:{title:t,slug:s,is_active:i}}),ee(null)},[F,L,J]),_e=e.useCallback(async(e,t)=>{ae(e.id);try{await E.mutateAsync({id:e.id,is_active:t}),await L({activityType:"course_update",entityType:"course",entityId:e.id,entityName:e.title,actionDescription:t?`Activated course: ${e.title}`:`Deactivated course: ${e.title}`,oldValues:{is_active:e.is_active},newValues:{is_active:t}})}catch{z({title:"Error",description:"Failed to update status",variant:"destructive"})}finally{ae(null)}},[L,z,E]);return ce?t.jsx(D,{children:t.jsx("p",{className:"p-8 text-muted-foreground",children:"Loading..."})}):t.jsxs(D,{children:[t.jsxs(l,{children:[t.jsx("meta",{name:"robots",content:"noindex,nofollow"}),t.jsx("title",{children:"Education Management - Admin - Delphi Global Research Center"})]}),t.jsxs("div",{className:"p-8",children:[t.jsxs("div",{className:"mb-8",children:[t.jsx("h1",{className:"font-heading text-3xl font-bold text-foreground mb-2",children:"Education Management"}),t.jsx("p",{className:"text-muted-foreground",children:"Manage courses and educational programs"})]}),t.jsxs(r,{className:"p-6",children:[t.jsxs("div",{className:"mb-6 flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between",children:[t.jsx("h2",{className:"text-xl font-semibold text-foreground",children:"Courses"}),t.jsxs("div",{className:"flex flex-col gap-3 sm:flex-row sm:items-center",children:[t.jsxs("div",{className:"relative flex-1 sm:max-w-xs",children:[t.jsx($,{className:"absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground"}),t.jsx(c,{placeholder:"Search courses...",value:B,onChange:e=>G(e.target.value),className:"pl-10"})]}),t.jsxs("p",{className:"text-sm text-muted-foreground whitespace-nowrap",children:[le," total",oe&&!ce?" · Updating…":""]})]}),t.jsxs(f,{open:Q,onOpenChange:e=>{Y(e),e||ge()},children:[t.jsx(v,{asChild:!0,children:t.jsxs(i,{children:[t.jsx(M,{className:"mr-2 h-4 w-4"}),"Add Course"]})}),t.jsxs(y,{className:"max-w-3xl max-h-[90vh] overflow-y-auto",children:[t.jsx(_,{children:t.jsx(b,{children:te?"Loading course…":H?"Edit Course":"Add New Course"})}),t.jsxs("form",{onSubmit:async e=>{e.preventDefault();const t=V.safeParse(he);if(!t.success)return void z({title:"Validation Error",description:t.error.errors[0].message,variant:"destructive"});const i={title:t.data.title,slug:t.data.slug,description:t.data.description,subtitle:t.data.subtitle||"",partner_info:t.data.partner_info||"",certificate_info:t.data.certificate_info||"",objectives:(t.data.objectives||"").split("\n").map(e=>e.trim()).filter(Boolean),schedule_info:t.data.schedule_info||"",application_info:t.data.application_info||"",youtube_link:t.data.youtube_link||"",application_status:t.data.application_status,is_active:t.data.is_active,display_order:t.data.display_order};
1if(H){const e={title:H.title,slug:H.slug,description:H.description,subtitle:H.subtitle,is_active:H.is_active,application_status:H.application_status};E.mutate({id:H.id,...i}),await L({activityType:"course_update",entityType:"course",entityId:H.id,entityName:i.title,actionDescription:`Updated course: ${i.title}`,oldValues:e,newValues:i})}else{const e=await s.mutateAsync(i);await L({activityType:"course_create",entityType:"course",entityId:null==e?void 0:e.id,entityName:i.title,actionDescription:`Created new course: ${i.title}`,newValues:i})}Y(!1),ge()},className:"space-y-4",children:[t.jsxs("div",{className:"grid grid-cols-1 gap-4 md:grid-cols-2",children:[t.jsxs("div",{className:"space-y-2",children:[t.jsx(u,{htmlFor:"title",children:"Title *"}),t.jsx(c,{id:"title",value:he.title,onChange:e=>{const t=e.target.value;xe({...he,title:t,slug:he.slug||t.toLowerCase().replace(/\s+/g,"-").replace(/[^a-z0-9-]/g,"")})},required:!0})]}),t.jsxs("div",{className:"space-y-2",children:[t.jsx(u,{htmlFor:"slug",children:"Slug * (URL-friendly)"}),t.jsx(c,{id:"slug",value:he.slug,onChange:e=>xe({...he,slug:e.target.value.toLowerCase().replace(/\s+/g,"-").replace(/[^a-z0-9-]/g,"")}),placeholder:"e.g., crisis-management-course",required:!0})]})]}),t.jsxs("div",{className:"space-y-2",children:[t.jsx(u,{htmlFor:"subtitle",children:"Subtitle"}),t.jsx(c,{id:"subtitle",value:he.subtitle,onChange:e=>xe({...he,subtitle:e.target.value})})]}),t.jsxs("div",{className:"space-y-2",children:[t.jsx(u,{htmlFor:"description",children:"Description *"}),t.jsx(T,{content:he.description,onChange:e=>xe({...he,description:e}),placeholder:"Add detailed course description with headings, lists, images, and links..."})]}),t.jsxs("div",{className:"space-y-2",children:[t.jsx(u,{htmlFor:"partner_info",children:"Partner Information"}),t.jsx(T,{content:he.partner_info,onChange:e=>xe({...he,partner_info:e}),placeholder:"Describe partner institutions, universities, or organizations..."})]}),t.jsxs("div",{className:"space-y-2",children:[t.jsx(u,{htmlFor:"certificate_info",children:"Certificate Information"}),t.jsx(T,{content:he.certificate_info,onChange:e=>xe({...he,certificate_info:e}),placeholder:"Explain certificates, credits, and completion requirements..."})]}),t.jsxs("div",{className:"space-y-2",children:[t.jsx(u,{htmlFor:"objectives",children:"Learning Objectives"}),t.jsx(d,{id:"objectives",value:he.objectives,onChange:e=>xe({...he,objectives:e.target.value}),placeholder:"One objective per line — each becomes a bullet on the public course page.",rows:5}),t.jsx("p",{className:"text-xs text-muted-foreground",children:"Enter one objective per line. Blank lines are ignored."})]}),t.jsxs("div",{className:"space-y-2",children:[t.jsx(u,{htmlFor:"schedule_info",children:"Schedule Information"}),t.jsx(T,{content:he.schedule_info,onChange:e=>xe({...he,schedule_info:e}),placeholder:"Outline schedule, weekly workload, and key dates..."})]}),t.jsxs("div",{className:"grid grid-cols-1 gap-4 md:grid-cols-2",children:[t.jsxs("div",{className:"space-y-2",children:[t.jsx(u,{htmlFor:"application_status",children:"Application Status"}),t.jsxs(N,{value:he.application_status,onValueChange:e=>xe({...he,application_status:e}),children:[t.jsx(C,{children:t.jsx(w,{})}),t.jsxs(k,{children:[t.jsx(A,{value:"accepting",children:"Accepting Applications"}),t.jsx(A,{value:"not_accepting",children:"Not Accepting"}),t.jsx(A,{value:"closed",children:"Closed"})]})]})]}),t.jsxs("div",{className:"space-y-2",children:[t.jsx(u,{htmlFor:"youtube_link",children:"YouTube Link"}),t.jsx(c,{id:"youtube_link",type:"url",value:he.youtube_link,onChange:e=>xe({...he,youtube_link:e.target.value})})]})]}),t.jsxs("div",{className:"space-y-2",children:[t.jsx(u,{htmlFor:"application_info",children:"Application Information"}),t.jsx(T,{content:he.application_info,onChange:e=>xe({...he,application_info:e}),placeholder:"Provide detailed application instructions, eligibility, and deadlines..."})]}),t.jsxs("div",{className:"grid grid-cols-1 gap-4 md:grid-cols-2",children:[t.jsxs("div",{className:"space-y-2",children:[t.jsx(u,{htmlFor:"display_order",children:"Display Order"}),t.jsx(c,{id:"display_order",type:"number",min:0,value:he.display_order,onChange:e=>{const t=parseInt(e.target.value,10);xe({...he,display_order:Number.isNaN(t)?0:t})}})]}),t.jsxs("div",{className:"flex items-center space-x-2",children:[t.jsx(S,{id:"is_active",checked:he.is_active,onCheckedChange:e=>xe({...he,is_active:e})}),t.jsx(u,{htmlFor:"is_active",children:"Active"})]})]}),t.jsxs("div",{className:"flex justify-end gap-2 pt-4",children:[t.jsx(i,{type:"button",variant:"outline",onClick:()=>{Y(!1),ge()},children:"Cancel"}),t.jsxs(i,{type:"submit",children:[H?"Update":"Create"," Course"]})]})]})]})]})]}),t.jsxs("div",{className:o("transition-opacity",oe&&!ce&&"opacity-70"),children:[t.jsxs(h,{children:[t.jsx(x,{children:t.jsxs(p,{children:[t.jsx(g,{children:"Title"}),t.jsx(g,{children:"Slug"}),t.jsx(g,{children:"Status"}),t.jsx(g,{children:"Active"}),t.jsx(g,{children:"Order"}),t.jsx(g,{className:"text-right",children:"Actions"})]})}),t.jsx(j,{children:0===ne.length?t.jsx(p,{children:t.jsx(m,{colSpan:6,className:"py-12 text-center text-muted-foreground",children:K.trim()?"No courses match your search.":"No courses yet."})}):ne.map(e=>t.jsx(R,{course:e,onEdit:fe,onDelete:ve,onToggleActive:_e,isTogglingActive:ie===e.id},e.id))})]}),le>0&&t.jsxs("div",{className:"flex flex-col gap-3 border-t border-border pt-4 mt-4 sm:flex-row sm:items-center sm:justify-between",children:[t.jsxs("p",{className:"text-sm text-muted-foreground",children:["Showing ",pe,"–",me," of ",le]}),t.jsxs("div",{className:"flex items-center gap-2",children:[t.jsx(i,{variant:"outline",size:"sm",disabled:I<=1||oe,onClick:()=>P(e=>Math.max(1,e-1)),children:"Previous"}),t.jsxs("span",{className:"text-sm text-muted-foreground tabular-nums",children:["Page ",I," of ",ue]}),t.jsx(i,{variant:"outline",size:"sm",disabled:I>=ue||oe,onClick:()=>P(e=>Math.min(ue,e+1)),children:"Next"})]})]})]})]}),J&&t.jsx("div",{className:"fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4",children:t.jsxs("div",{className:"w-full max-w-md rounded-lg bg-card p-6 shadow-lg",children:[t.jsx("h2",{className:"text-lg font-semibold",children:"Delete course?"}),t.jsxs("p",{className:"mt-2 text-sm text-muted-foreground",children:['Permanently delete "',J.title,'"?']}),t.jsxs("div",{className:"mt-6 flex justify-end gap-2",children:[t.jsx(i,{variant:"outline",onClick:()=>ee(null),children:"Cancel"}),t.jsx(i,{variant:"destructive",onClick:()=>{ye()},children:"Delete"})]})]})})]})]})};export{G 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.