PageSourceSearch

https://closethegapinseniorcare.org/assets/MarketingBriefsPage-BV4nYdMH.js

js closethegapinseniorcare.org collected 2026-10-08 05:35:41 UTC 15,342 bytes, 2 lines download raw bytes

1import{r as w,c as C,j as e,C as O,w as Q,bJ as H,x as J,y as U,d as Y,B as m,f as g,h as ee,A as ae,b as se,m as v,q as u,n as d,o as N,a1 as M,F as R}from"./index-DbHtWmcn.js";import{L as ie}from"./Layout-0N5DPfFC.js";import{I as te}from"./input-BesI745p.js";import{T as z}from"./textarea-Btt46j-R.js";import{A as re}from"./arrow-left-BowHSGe_.js";import{S as G}from"./save-Bafluf7o.js";import{I as ne}from"./image-plus-B0Ize7ud.js";import{D as le}from"./download-BGDZiA1Q.js";import{L as oe}from"./link-2-kjQ2NvFg.js";const de=["January","February","March","April","May","June","July","August","September","October","November","December"],k=["briefTone","briefMessage","briefPalette","briefTypography","briefImageryNotes","briefDosDonts"];function ce(p){const n=k.filter(l=>String(p[l]||"").trim()).length;return n===0?{label:"Not started",variant:"outline"}:n<k.length?{label:`In progress (${n}/${k.length})`,variant:"secondary"}:{label:"Complete",variant:"default"}}function me({campaignId:p,onBack:n}){var L,S,q,A,K,B;const{toast:l}=se(),x=[`/api/campaigns/${p}/plan`],{data:s,isLoading:h,error:c}=C({queryKey:x,queryFn:async()=>(await d("GET",`/api/campaigns/${p}/plan`)).json()}),[o,$]=w.useState({briefTone:"",briefMessage:"",briefPalette:"",briefTypography:"",briefImageryNotes:"",briefDosDonts:"",briefLinks:""}),[t,b]=w.useState(!1);w.useEffect(()=>{s!=null&&s.plan&&!t&&$({briefTone:s.plan.briefTone||"",briefMessage:s.plan.briefMessage||"",briefPalette:s.plan.briefPalette||"",briefTypography:s.plan.briefTypography||"",briefImageryNotes:s.plan.briefImageryNotes||"",briefDosDonts:s.plan.briefDosDonts||"",briefLinks:s.plan.briefLinks||""})},[(L=s==null?void 0:s.plan)==null?void 0:L.id,(S=s==null?void 0:s.plan)==null?void 0:S.updatedAt]);const F=a=>i=>{$(r=>({...r,[a]:i})),b(!0)},f=v({mutationFn:async()=>(await d("PATCH",`/api/campaign-plans/${s.plan.id}`,o)).json(),onSuccess:()=>{b(!1),u.invalidateQueries({queryKey:x}),u.invalidateQueries({queryKey:["/api/campaigns/briefs-overview"]}),l({title:"Creative brief saved"})},onError:a=>l({title:"Couldn't save",description:a==null?void 0:a.message,variant:"destructive"})}),T=[`/api/campaign-plans/${(q=s==null?void 0:s.plan)==null?void 0:q.id}/brief-images`],{data:_=[]}=C({queryKey:T,queryFn:async()=>(await d("GET",`/api/campaign-plans/${s.plan.id}/brief-images`)).json(),enabled:!!((A=s==null?void 0:s.plan)!=null&&A.id)}),D=v({mutationFn:async a=>{const i=new FormData;i.append("image",a);const r=await fetch(`/api/campaign-plans/${s.plan.id}/brief-images`,{method:"POST",body:i,credentials:"include"});if(!r.ok){const j=await r.json().catch(()=>({}));throw new Error(j.message||"Upload failed")}return r.json()},onSuccess:()=>u.invalidateQueries({queryKey:T}),onError:a=>l({title:"Couldn't upload image",description:a==null?void 0:a.message,variant:"destructive"})}),W=v({mutationFn:async a=>(await d("DELETE",`/api/campaign-plans/${s.plan.id}/brief-images/${a}`)).json(),onSuccess:()=>u.invalidateQueries({queryKey:T}),onError:a=>l({title:"Couldn't remove image",description:a==null?void 0:a.message,variant:"destructive"})}),P=[`/api/campaign-plans/${(K=s==null?void 0:s.plan)==null?void 0:K.id}/brief-files`],{data:E=[]}=C({queryKey:P,queryFn:async()=>(await d("GET",`/api/campaign-plans/${s.plan.id}/brief-files`)).json(),enabled:!!((B=s==null?void 0:s.plan)!=null&&B.id)}),I=v({mutationFn:async a=>{const i=new FormData;i.append("file",a);const r=await fetch(`/api/campaign-plans/${s.plan.id}/brief-files`,{method:"POST",body:i,credentials:"include"});if(!r.ok){const j=await r.json().catch(()=>({}));throw new Error(j.message||"Upload failed")}return r.json()},onSuccess:()=>u.invalidateQueries({queryKey:P}),onError:a=>l({title:"Couldn't upload file",description:a==null?void 0:a.message,variant:"destructive"})}),X=v({mutationFn:async a=>(await d("DELETE",`/api/campaign-plans/${s.plan.id}/brief-files/${a}`)).json(),onSuccess:()=>u.invalidateQueries({queryKey:P}),onError:a=>l({title:"Couldn't remove file",description:a==null?void 0:a.message,variant:"destructive"})}),Z=o.briefPalette.split(",").map(a=>a.trim()).filter(a=>/^#[0-9a-fA-F]{3,8}$/.test(a));if(h)return e.jsxs("div",{className:"flex items-center gap-2 py-10 text-sm text-muted-foreground",children:[e.jsx(g,{className:"h-4 w-4 animate-spin"})," Loading creative brief…"]});if(c||!s)return e.jsxs("p",{className:"py-10 text-sm text-destructive",children:["Couldn't load this brief. ",String((c==null?void 0:c.message)||"")]});const y=(a,i,r,j=3)=>e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(N,{htmlFor:`brief-${a}`,children:i}),e.jsx(z,{id:`brief-${a}`,rows:j,value:o[a],placeholder:r,onChange:V=>F(a)(V.target.value),"data-testid":`textarea-${a}`})]});return e.jsxs("div",{className:"space-y-5",children:[e.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-3",children:[e.jsxs(m,{variant:"ghost",size:"sm",className:"-ml-2 text-muted-foreground hover:text-primary",onClick:n,"data-testid":"button-back-to-briefs",children:[e.jsx(re,{className:"mr-1.5 h-4 w-4"})," All briefs"]}),e.jsxs(m,{size:"sm",onClick:()=>f.mutate(),disabled:!t||f.isPending,"data-testid":"button-save-brief",children:[f.isPending?e.jsx(g,{className:"mr-1.5 h-4 w-4 animate-spin"}):e.jsx(G,{className:"mr-1.5 h-4 w-4"}),"Save brief"]})]}),e.jsxs(O,{className:"overflow-hidden border-primary/20 shadow-sm",children:[e.jsx(Q,{className:"border-b border-primary/10 bg-primary/[0.035] px-5 py-5 sm:px-7",children:e.jsxs("div",{className:"flex items-start gap-3",children:[e.jsx("div",{className:"rounded-xl bg-primary/10 p-2.5 text-primary",children:e.jsx(H,{className:"h-5 w-5"})}),e.jsxs("div",{children:[e.jsx(J,{className:"text-xl","data-testid":"text-brief-campaign-name",children:s.campaign.name}),e.jsx(U,{className:"mt-1",children:"Creative Brief — the marketing guide for producing this campaign's assets. Edits here appear on the Campaign Plan page too."})]})]})}),e.jsxs(Y,{className:"space-y-5 px-5 py-6 sm:px-7",children:[e.jsxs("div",{className:"rounded-lg border bg-muted/40 p-4 space-y-3","data-testid":"section-plan-reference",children:[e.jsx("p",{className:"text-sm font-semibold text-[#084E7F]",children:"From the Campaign Plan"}),e.jsx("dl",{className:"grid gap-x-6 gap-y-3 sm:grid-cols-2",children:[["Purpose",s.campaign.purpose],["Primary ask",s.campaign.ask],["Goal",s.campaign.goal],["Channels",s.c
1ampaign.channels],["Campaign summary & source message",s.plan.summary],["The offer",s.plan.offer],["Audience notes",s.plan.audienceNotes],["Fund designation",s.plan.fundDesignation],["Budget",s.plan.budget],["Matching / deadline note",s.plan.matchingNote]].filter(([,a])=>String(a||"").trim()).map(([a,i])=>e.jsxs("div",{className:a==="Campaign summary & source message"||a==="The offer"?"sm:col-span-2":"",children:[e.jsx("dt",{className:"text-xs font-medium uppercase tracking-wide text-muted-foreground",children:a}),e.jsx("dd",{className:"mt-0.5 whitespace-pre-wrap text-sm",children:i})]},a))}),![s.campaign.purpose,s.campaign.ask,s.campaign.goal,s.plan.summary,s.plan.offer].some(a=>String(a||"").trim())&&e.jsx("p",{className:"text-sm text-muted-foreground",children:"Nothing entered on this campaign's Plan yet — details Development adds there will appear here for reference."})]}),y("briefTone","Tone & voice","How the campaign should sound — warm, urgent, hopeful…"),y("briefMessage","Message & story angle","The creative interpretation of the approved source message."),e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(N,{htmlFor:"brief-palette-input",children:"Color palette"}),e.jsx("div",{className:"flex flex-wrap items-center gap-2",children:Z.map(a=>e.jsxs("span",{className:"flex items-center gap-1.5 rounded-md border px-2 py-1 text-xs",children:[e.jsx("span",{className:"inline-block h-4 w-4 rounded-sm border",style:{backgroundColor:a}}),a]},a))}),e.jsx(te,{id:"brief-palette-input",value:o.briefPalette,placeholder:"Comma-separated hex colors, e.g. #084E7F, #F4A300",onChange:a=>F("briefPalette")(a.target.value),"data-testid":"input-briefPalette"})]}),y("briefTypography","Typography & style","Fonts, sizes, and style notes for produced assets."),y("briefImageryNotes","Imagery notes","Written guidance for photos/graphics — subjects, mood, framing."),e.jsxs("div",{className:"space-y-2",children:[e.jsx(N,{children:"Reference images"}),e.jsxs("div",{className:"flex flex-wrap gap-3",children:[_.map(a=>e.jsxs("div",{className:"group relative h-24 w-24 overflow-hidden rounded-lg border","data-testid":`img-brief-${a.id}`,children:[e.jsx("img",{src:a.url,alt:a.filename,className:"h-full w-full object-cover"}),e.jsx("button",{type:"button",className:"absolute right-1 top-1 rounded-full bg-black/60 p-1 text-white opacity-0 transition-opacity group-hover:opacity-100",onClick:()=>W.mutate(a.id),"aria-label":`Remove ${a.filename}`,"data-testid":`button-delete-brief-image-${a.id}`,children:e.jsx(M,{className:"h-3.5 w-3.5"})})]},a.id)),e.jsxs("label",{className:"flex h-24 w-24 cursor-pointer flex-col items-center justify-center gap-1 rounded-lg border border-dashed text-xs text-muted-foreground transition-colors hover:border-primary hover:text-primary",children:[D.isPending?e.jsx(g,{className:"h-5 w-5 animate-spin"}):e.jsx(ne,{className:"h-5 w-5"}),"Add image",e.jsx("input",{type:"file",accept:"image/jpeg,image/png,image/webp,image/gif",className:"hidden",onChange:a=>{var r;const i=(r=a.target.files)==null?void 0:r[0];i&&D.mutate(i),a.target.value=""},"data-testid":"input-upload-brief-image"})]})]})]}),y("briefDosDonts","Do's & don'ts","Guardrails — what to always do, and what to avoid."),e.jsxs("div",{className:"space-y-2",children:[e.jsx(N,{children:"Reference files"}),E.length>0&&e.jsx("div",{className:"divide-y rounded-lg border",children:E.map(a=>{var i;return e.jsxs("div",{className:"flex items-center gap-3 px-3 py-2","data-testid":`brief-file-${a.id}`,children:[e.jsx(R,{className:"h-4 w-4 shrink-0 text-primary"}),e.jsx("span",{className:"min-w-0 flex-1 truncate text-sm",children:a.filename}),e.jsx(m,{asChild:!0,variant:"ghost",size:"icon",className:"h-8 w-8","data-testid":`button-download-brief-file-${a.id}`,children:e.jsx("a",{href:`/api/campaign-plans/${(i=s==null?void 0:s.plan)==null?void 0:i.id}/brief-files/${a.id}/download`,download:a.filename,"aria-label":`Download ${a.filename}`,children:e.jsx(le,{className:"h-4 w-4"})})}),e.jsx(m,{type:"button",variant:"ghost",size:"icon",className:"h-8 w-8 text-muted-foreground hover:text-destructive",onClick:()=>X.mutate(a.id),"aria-label":`Remove ${a.filename}`,"data-testid":`button-remove-brief-file-${a.id}`,children:e.jsx(M,{className:"h-4 w-4"})})]},a.id)})}),e.jsxs("label",{className:"flex w-fit cursor-pointer items-center gap-2 rounded-lg border border-dashed px-3 py-2 text-sm text-muted-foreground transition-colors hover:border-primary hover:text-primary",children:[I.isPending?e.jsx(g,{className:"h-4 w-4 animate-spin"}):e.jsx(R,{className:"h-4 w-4"}
1),"Add file",e.jsx("input",{type:"file",accept:".pdf,.png,.jpg,.jpeg,.webp,.gif,.zip",className:"hidden",onChange:a=>{var r;const i=(r=a.target.files)==null?void 0:r[0];i&&I.mutate(i),a.target.value=""},"data-testid":"input-upload-brief-file"})]}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"Partner-provided PDFs and other reference documents (PDF, image, or ZIP, up to 20MB). Uploads save immediately."})]}),e.jsxs("div",{className:"space-y-1.5",children:[e.jsxs(N,{htmlFor:"brief-briefLinks",children:["Reference links ",e.jsx("span",{className:"font-normal text-muted-foreground",children:"(optional)"})]}),e.jsx(z,{id:"brief-briefLinks",rows:2,value:o.briefLinks,placeholder:`One URL per line, eg:
2https://partner.org/brand`,onChange:a=>F("briefLinks")(a.target.value),"data-testid":"textarea-briefLinks"}),o.briefLinks.split(/\n+/).map(a=>a.trim()).filter(a=>/^https?:\/\//i.test(a)).length>0&&e.jsx("div",{className:"flex flex-wrap gap-2",children:o.briefLinks.split(/\n+/).map(a=>a.trim()).filter(a=>/^https?:\/\//i.test(a)).map((a,i)=>e.jsxs("a",{href:a,target:"_blank",rel:"noopener noreferrer",className:"flex items-center gap-1.5 rounded-md border px-2 py-1 text-xs text-primary hover:bg-primary/5","data-testid":`link-brief-ref-${i}`,children:[e.jsx(oe,{className:"h-3.5 w-3.5"}),e.jsx("span",{className:"max-w-[16rem] truncate",children:a.replace(/^https?:\/\//i,"")})]},`${a}-${i}`))})]}),e.jsx("div",{className:"flex justify-end",children:e.jsxs(m,{onClick:()=>f.mutate(),disabled:!t||f.isPending,"data-testid":"button-save-brief-bottom",children:[f.isPending?e.jsx(g,{className:"mr-1.5 h-4 w-4 animate-spin"}):e.jsx(G,{className:"mr-1.5 h-4 w-4"}),"Save brief"]})})]})]})]})}function ve(){const p=new Date().getFullYear(),[n,l]=w.useState(p),[x,s]=w.useState(null),{data:h}=C({queryKey:["/api/campaigns/years"],queryFn:async()=>(await d("GET","/api/campaigns/years")).json()}),c=(h==null?void 0:h.years)??[],{data:o=[],isLoading:$}=C({queryKey:["/api/campaigns/briefs-overview",{year:n}],queryFn:async()=>(await d("GET",`/api/campaigns/briefs-overview?year=${n}`)).json()});return e.jsx(ie,{navigationKey:"admin",title:"Creative Briefs",children:e.jsx("div",{className:"mx-auto max-w-5xl space-y-6 p-4 sm:p-8",children:x!==null?e.jsx(me,{campaignId:x,onBack:()=>s(null)}):e.jsxs(O,{className:"overflow-hidden border-primary/20 shadow-sm",children:[e.jsx(Q,{className:"border-b border-primary/10 bg-primary/[0.035] px-5 py-5 sm:px-7",children:e.jsxs("div",{className:"flex items-start gap-3",children:[e.jsx("div",{className:"rounded-xl bg-primary/10 p-2.5 text-primary",children:e.jsx(H,{className:"h-5 w-5"})}),e.jsxs("div",{children:[e.jsx(J,{className:"text-xl",children:"Creative Briefs"}),e.jsx(U,{className:"mt-1",children:"Every campaign's Creative Brief in one place — the same briefs as on each Campaign Plan."})]})]})}),e.jsxs(Y,{className:"space-y-4 px-5 py-6 sm:px-7",children:[c.length>1&&e.jsx("div",{className:"flex flex-wrap gap-2",children:c.map(t=>e.jsx(m,{size:"sm",variant:t===n?"default":"outline",onClick:()=>l(t),"data-testid":`button-briefs-year-${t}`,children:t},t))}),$?e.jsx("div",{className:"flex justify-center py-10",children:e.jsx(g,{className:"h-5 w-5 animate-spin text-muted-foreground"})}):o.length===0?e.jsxs("p",{className:"py-8 text-center text-sm text-muted-foreground",children:["No campaigns for ",n," yet. Add campaigns on the Timelines page first."]}):e.jsx("div",{className:"divide-y rounded-xl border border-border/70",children:o.map(t=>{const b=ce(t);return e.jsxs("div",{className:"flex flex-wrap items-center gap-3 px-4 py-3.5 transition-colors hover:bg-primary/[0.025]","data-testid":`row-brief-${t.campaignId}`,children:[e.jsxs("div",{className:"min-w-0 flex-1",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx("span",{className:"font-semibold",children:t.campaignName}),e.jsx(ee,{variant:b.variant,className:"text-xs","data-testid":`badge-brief-status-${t.campaignId}`,children:b.label})]}),e.jsxs("p",{className:"mt-0.5 text-sm text-muted-foreground",children:[de[(t.month??1)-1]??"",t.tier?` · Tier ${t.tier}`:""]})]}),e.jsxs(m,{size:"sm",variant:"outline",onClick:()=>s(t.campaignId),"data-testid":`button-open-brief-${t.campaignId}`,children:["Open brief ",e.jsx(ae,{className:"ml-1.5 h-3.5 w-3.5"})]})]},t.campaignId)})})]})]})})})}export{ve 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.