From 81deaf447f4d13872b99bf972429e05d4e8cea1b Mon Sep 17 00:00:00 2001 From: Marc Mintel Date: Thu, 12 Feb 2026 21:24:15 +0100 Subject: [PATCH] fix(acquisition): standardize bundling and externalize React/PDF dependencies - Added JSX support to esbuild configuration. - Externalized react, react-dom, and @react-pdf/renderer to avoid redundant bundling. - Updated acquisition-library exports for modular PDF generation. --- .../extensions/acquisition-manager/index.js | 1 + .../acquisition-manager/package.json | 30 +++ directus/extensions/acquisition/package.json | 27 +++ directus/extensions/customer-manager/index.js | 1 + .../extensions/customer-manager/package.json | 30 +++ .../extensions/feedback-commander/index.js | 1 + .../feedback-commander/package.json | 30 +++ directus/extensions/people-manager/index.js | 1 + .../extensions/people-manager/package.json | 30 +++ directus/uploads/directus-health-file | 1 + packages/acquisition-library/build.mjs | 8 +- .../pdf/modules/BrandingModules.tsx | 218 ++++++++++++++++++ packages/acquisition-library/src/index.ts | 10 + packages/acquisition/build.mjs | 10 +- 14 files changed, 394 insertions(+), 4 deletions(-) create mode 100644 directus/extensions/acquisition-manager/index.js create mode 100644 directus/extensions/acquisition-manager/package.json create mode 100644 directus/extensions/acquisition/package.json create mode 100644 directus/extensions/customer-manager/index.js create mode 100644 directus/extensions/customer-manager/package.json create mode 100644 directus/extensions/feedback-commander/index.js create mode 100644 directus/extensions/feedback-commander/package.json create mode 100644 directus/extensions/people-manager/index.js create mode 100644 directus/extensions/people-manager/package.json create mode 100644 directus/uploads/directus-health-file create mode 100644 packages/acquisition-library/src/components/pdf/modules/BrandingModules.tsx diff --git a/directus/extensions/acquisition-manager/index.js b/directus/extensions/acquisition-manager/index.js new file mode 100644 index 0000000..533d6a0 --- /dev/null +++ b/directus/extensions/acquisition-manager/index.js @@ -0,0 +1 @@ +import{useApi as e,defineModule as a}from"@directus/extensions-sdk";import{defineComponent as t,ref as l,computed as n,onMounted as i,resolveComponent as s,resolveDirective as o,openBlock as d,createBlock as r,withCtx as u,createVNode as c,createElementBlock as v,Fragment as p,renderList as m,createTextVNode as f,toDisplayString as g,createCommentVNode as y,createElementVNode as b,withDirectives as h}from"vue";var _=Object.defineProperty,x=Object.getOwnPropertySymbols,w=Object.prototype.hasOwnProperty,k=Object.prototype.propertyIsEnumerable,V=(e,a,t)=>a in e?_(e,a,{enumerable:!0,configurable:!0,writable:!0,value:t}):e[a]=t;const A={class:"content-wrapper"},C={key:0,class:"empty-state"},$={class:"header"},U={class:"header-left"},F={class:"title"},O={class:"subtitle"},P=["href"],E={class:"header-right"},S={class:"sections"},j={class:"main-info"},L={class:"form-grid"},z={class:"field"},q={key:1,class:"value text-subdued"},B={class:"field"},N={class:"value"},D={class:"field full"},M={class:"value text-block"},I={key:0,class:"ai-observations"},T={class:"metrics"},K={class:"page-title"},G={class:"page-url"},R={class:"drawer-content"},W={class:"form-section"},H={class:"field"},J={class:"field"},Q={class:"field"},X={class:"field"},Y={class:"field"},Z={class:"field"},ee={class:"drawer-actions"};var ae=t({__name:"module",setup(a){const t=e(),_=l([]),ae=l(null),te=l(!1),le=l(!1),ne=l(!1),ie=l(!1),se=l(!1),oe=l(null),de=l({company_name:"",website_url:"",contact_name:"",contact_email:"",contact_person:null,briefing:"",status:"new"}),re=l([]),ue=n(()=>re.value.map(e=>({text:`${e.first_name} ${e.last_name}`,value:e.id})));function ce(e){const a=re.value.find(a=>a.id===e);return a?`${a.first_name} ${a.last_name}`:e}const ve=n(()=>_.value.find(e=>e.id===ae.value));async function pe(){const[e,a]=await Promise.all([t.get("/items/leads",{params:{sort:"-date_created"}}),t.get("/items/people",{params:{sort:"last_name"}})]);_.value=e.data.data,re.value=a.data.data,!ae.value&&_.value.length>0&&(ae.value=_.value[0].id)}async function me(){if(ae.value){te.value=!0;try{await t.post(`/acquisition/audit/${ae.value}`),oe.value={type:"success",message:"Audit erfolgreich gestartet!"},await pe()}catch(e){oe.value={type:"danger",message:`Fehler beim Audit: ${e.message}`}}finally{te.value=!1}}}async function fe(){if(ae.value){ne.value=!0;try{await t.post(`/acquisition/audit-email/${ae.value}`),oe.value={type:"success",message:"Audit E-Mail versendet!"},await pe()}catch(e){oe.value={type:"danger",message:`Fehler beim Versenden: ${e.message}`}}finally{ne.value=!1}}}async function ge(){if(ae.value){le.value=!0;try{await t.post(`/acquisition/estimate/${ae.value}`),oe.value={type:"success",message:"Angebot (PDF) wurde generiert!"},await pe()}catch(e){oe.value={type:"danger",message:`Fehler bei PDF Generierung: ${e.message}`}}finally{le.value=!1}}}async function ye(){if(ae.value){ne.value=!0;try{await t.post(`/acquisition/estimate-email/${ae.value}`),oe.value={type:"success",message:"Angebot erfolgreich versendet!"},await pe()}catch(e){oe.value={type:"danger",message:`Fehler beim Versenden: ${e.message}`}}finally{ne.value=!1}}}function be(){var e;(null==(e=ve.value)?void 0:e.audit_pdf_path)&&window.open(`${window.location.origin}/assets/${ve.value.audit_pdf_path}`,"_blank")}async function he(){if(de.value.company_name){se.value=!0;try{const e=((e,a)=>{for(var t in a||(a={}))w.call(a,t)&&V(e,t,a[t]);if(x)for(var t of x(a))k.call(a,t)&&V(e,t,a[t]);return e})({id:crypto.randomUUID()},de.value);await t.post("/items/leads",e),oe.value={type:"success",message:"Lead erfolgreich registriert!"},ie.value=!1,await pe(),ae.value=e.id,de.value={company_name:"",website_url:"",contact_name:"",contact_email:"",contact_person:null,briefing:"",status:"new"}}catch(e){oe.value={type:"danger",message:`Fehler beim Speichern: ${e.message}`}}finally{se.value=!1}}}function _e(e){switch(e){case"new":return"fiber_new";case"auditing":return"hourglass_empty";case"audit_ready":return"check_circle";case"contacted":return"mail_outline";default:return"help_outline"}}function xe(e){switch(e){case"new":return"var(--theme--primary)";case"auditing":return"var(--theme--warning)";case"audit_ready":return"var(--theme--success)";case"contacted":return"var(--theme--secondary)";default:return"var(--theme--foreground-subdued)"}}return i(pe),(e,a)=>{const t=s("v-icon"),l=s("v-list-item-icon"),n=s("v-text-overflow"),i=s("v-list-item-content"),x=s("v-list-item"),w=s("v-divider"),k=s("v-list"),V=s("v-notice"),re=s("v-button"),pe=s("v-info"),we=s("v-table"),ke=s("v-input"),Ve=s("v-textarea"),Ae=s("v-select"),Ce=s("v-drawer"),$e=s("private-view"),Ue=o("tooltip");return d(),r($e,{title:"Acquisition Manager"},{navigation:u(()=>[c(k,{nav:""},{default:u(()=>[c(x,{onClick:a[0]||(a[0]=e=>ie.value=!0),clickable:""},{default:u(()=>[c(l,null,{default:u(()=>[c(t,{name:"add",color:"var(--theme--primary)"})]),_:1}),c(i,null,{default:u(()=>[c(n,{text:"Neuen Lead anlegen"})]),_:1})]),_:1}),c(w),(d(!0),v(p,null,m(_.value,e=>(d(),r(x,{key:e.id,active:ae.value===e.id,class:"lead-item",clickable:"",onClick:a=>{return t=e.id,void(ae.value=t);var t}},{default:u(()=>[c(l,null,{default:u(()=>[c(t,{name:_e(e.status),color:xe(e.status)},null,8,["name","color"])]),_:2},1024),c(i,null,{default:u(()=>[c(n,{text:e.company_name},null,8,["text"])]),_:2},1024)]),_:2},1032,["active","onClick"]))),128))]),_:1})]),"title-outer:after":u(()=>[oe.value?(d(),r(V,{key:0,type:oe.value.type,onClose:a[1]||(a[1]=e=>oe.value=null),dismissible:""},{default:u(()=>[f(g(oe.value.message),1)]),_:1},8,["type"])):y("v-if",!0)]),default:u(()=>{var e;return[b("div",A,[c(V,{type:"success",style:{"margin-bottom":"16px"}},{default:u(()=>[f(" DEBUG: Module Version 1.1.0 - Native Build - "+g((new Date).toISOString()),1)]),_:1}),ve.value?(d(),v(p,{key:1},[b("header",$,[b("div",U,[b("h1",F,g(ve.value.company_name),1),b("p",O,[c(t,{name:"language","x-small":""}),b("a",{href:ve.value.website_url,target:"_blank",class:"url-link"},g(ve.value.website_url.replace(/^https?:\/\//,"")),9,P),f(" · Status: "+g(ve.value.status.toUpperCase()),1)])]),b("div",E,["new"===ve.value.status?(d(),r(re,{key:0,secondary:"",loading:te.value,onClick:me},{default:u(()=>[c(t,{name:"settings_suggest",left:""}),a[15]||(a[15]=f(" Audit starten ",-1))]),_:1},8,["loading"])):y("v-if",!0),"audit_ready"===ve.value.status?(d(),v(p,{key:1},[c(re,{secondary:"",loading:ne.value,onClick:fe},{default:u(()=>[c(t,{name:"mail",left:""}),a[16]||(a[16]=f(" Audit E-Mail ",-1))]),_:1},8,["loading"]),c(re,{loading:le.value,onClick:ge},{default:u(()=>[c(t,{name:"picture_as_pdf",left:""}),a[17]||(a[17]=f(" PDF Erstellen ",-1))]),_:1},8,["loading"])],64)):y("v-if",!0),ve.value.audit_pdf_path?h((d(),r(re,{key:2,secondary:"",icon:"",onClick:be},{default:u(()=>[c(t,{name:"open_in_new"})]),_:1})),[[Ue,"PDF öffnen",void 0,{bottom:!0}]]):y("v-if",!0),ve.value.audit_pdf_path?(d(),r(re,{key:3,primary:"",loading:ne.value,onClick:ye},{default:u(()=>[c(t,{name:"send",left:""}),a[18]||(a[18]=f(" Angebot senden ",-1))]),_:1},8,["loading"])):y("v-if",!0)])]),b("div",S,[b("div",j,[b("div",L,[b("div",z,[a[19]||(a[19]=b("span",{class:"label"},"Kontaktperson",-1)),ve.value.contact_person?(d(),v("div",{key:0,class:"value person-link",onClick:a[3]||(a[3]=e=>{return a=ve.value.contact_person,void(oe.value={type:"info",message:`Navigiere zu Person: ${a}`});var a})},g(ce(ve.value.contact_person)),1)):(d(),v("div",q,"Keine Person verknüpft"))]),b("div",B,[a[20]||(a[20]=b("span",{class:"label"},"E-Mail (Legacy)",-1)),b("div",N,g(ve.value.contact_email||"—"),1)]),b("div",D,[a[21]||(a[21]=b("span",{class:"label"},"Briefing / Fokus",-1)),b("div",M,g(ve.value.briefing||"Kein Briefing hinterlegt."),1)])])]),c(w),ve.value.ai_state?(d(),v("div",I,[a[22]||(a[22]=b("h3",{class:"section-title"},"AI Observations & Estimation",-1)),b("div",T,[c(pe,{label:"Projekt-Modus",value:ve.value.ai_state.projectType||"Unbekannt"},null,8,["value"]),c(pe,{label:"Seitenanzahl",value:(null==(e=ve.value.ai_state.sitemap)?void 0:e.length)||"0"},null,8,["value"])]),ve.value.ai_state.sitemap?(d(),r(we,{key:0,headers:[{text:"Seite",value:"title"},{text:"URL",value:"url"}],items:ve.value.ai_state.sitemap,class:"observation-table"},{"item.title":u(({item:e})=>[b("span",K,g(e.title),1)]),"item.url":u(({item:e})=>[b("span",G,g(e.url),1)]),_:2},1032,["items"])):y("v-if",!0)])):y("v-if",!0)])],64)):(d(),v("div",C,[c(pe,{title:"Lead auswählen",icon:"auto_awesome",center:""},{default:u(()=>[a[13]||(a[13]=f(" Wähle einen Lead in der Navigation aus oder ",-1)),c(re,{"x-small":"",onClick:a[2]||(a[2]=e=>ie.value=!0)},{default:u(()=>[...a[12]||(a[12]=[f("registriere einen neuen Lead",-1)])]),_:1}),a[14]||(a[14]=f(". ",-1))]),_:1})]))]),c(Ce,{modelValue:ie.value,"onUpdate:modelValue":a[10]||(a[10]=e=>ie.value=e),title:"Neuen Lead registrieren",icon:"person_add",onCancel:a[11]||(a[11]=e=>ie.value=!1)},{default:u(()=>[b("div",R,[b("div",W,[b("div",H,[a[23]||(a[23]=b("span",{class:"label"},"Firma",-1)),c(ke,{modelValue:de.value.company_name,"onUpdate:modelValue":a[4]||(a[4]=e=>de.value.company_name=e),placeholder:"z.B. Schmidt GmbH",autofocus:""},null,8,["modelValue"])]),b("div",J,[a[24]||(a[24]=b("span",{class:"label"},"Website URL",-1)),c(ke,{modelValue:de.value.website_url,"onUpdate:modelValue":a[5]||(a[5]=e=>de.value.website_url=e),placeholder:"https://..."},null,8,["modelValue"])]),b("div",Q,[a[25]||(a[25]=b("span",{class:"label"},"Ansprechpartner",-1)),c(ke,{modelValue:de.value.contact_name,"onUpdate:modelValue":a[6]||(a[6]=e=>de.value.contact_name=e),placeholder:"Vorname Nachname"},null,8,["modelValue"])]),b("div",X,[a[26]||(a[26]=b("span",{class:"label"},"E-Mail Adresse",-1)),c(ke,{modelValue:de.value.contact_email,"onUpdate:modelValue":a[7]||(a[7]=e=>de.value.contact_email=e),placeholder:"email@beispiel.de",type:"email"},null,8,["modelValue"])]),b("div",Y,[a[27]||(a[27]=b("span",{class:"label"},"Briefing / Fokus",-1)),c(Ve,{modelValue:de.value.briefing,"onUpdate:modelValue":a[8]||(a[8]=e=>de.value.briefing=e),placeholder:"Besonderheiten für das Audit..."},null,8,["modelValue"])]),b("div",Z,[a[28]||(a[28]=b("span",{class:"label"},"Kontaktperson (Optional)",-1)),c(Ae,{modelValue:de.value.contact_person,"onUpdate:modelValue":a[9]||(a[9]=e=>de.value.contact_person=e),items:ue.value,placeholder:"Person auswählen..."},null,8,["modelValue","items"])])]),b("div",ee,[c(re,{primary:"",block:"",loading:se.value,onClick:he},{default:u(()=>[...a[29]||(a[29]=[f("Lead speichern",-1)])]),_:1},8,["loading"])])])]),_:1},8,["modelValue"])]}),_:1})}}}),te=[],le=[];!function(e,a){if(e&&"undefined"!=typeof document){var t,l=!0===a.prepend?"prepend":"append",n=!0===a.singleTag,i="string"==typeof a.container?document.querySelector(a.container):document.getElementsByTagName("head")[0];if(n){var s=te.indexOf(i);-1===s&&(s=te.push(i)-1,le[s]={}),t=le[s]&&le[s][l]?le[s][l]:le[s][l]=o()}else t=o();65279===e.charCodeAt(0)&&(e=e.substring(1)),t.styleSheet?t.styleSheet.cssText+=e:t.appendChild(document.createTextNode(e))}function o(){var e=document.createElement("style");if(e.setAttribute("type","text/css"),a.attributes)for(var t=Object.keys(a.attributes),n=0;n{const t=e.__vccOpts||e;for(const[e,l]of a)t[e]=l;return t})(ae,[["__scopeId","data-v-6a55edd7"],["__file","module.vue"]]),ie=a({id:"acquisition-manager",name:"Acquisition",icon:"auto_awesome",routes:[{path:"",component:ne},{path:":id",component:ne,props:!0}]});export{ie as default}; diff --git a/directus/extensions/acquisition-manager/package.json b/directus/extensions/acquisition-manager/package.json new file mode 100644 index 0000000..14990bd --- /dev/null +++ b/directus/extensions/acquisition-manager/package.json @@ -0,0 +1,30 @@ +{ + "name": "acquisition-manager", + "description": "Custom High-Fidelity Acquisition Management for Directus", + "icon": "account_balance_wallet", + "version": "1.7.12", + "type": "module", + "keywords": [ + "directus", + "directus-extension", + "directus-extension-module" + ], + "files": [ + "dist" + ], + "directus:extension": { + "type": "module", + "path": "index.js", + "source": "src/index.ts", + "host": "*", + "name": "Acquisition Manager" + }, + "scripts": { + "build": "directus-extension build && (cp -f dist/index.js index.js 2>/dev/null || true)", + "dev": "directus-extension build -w" + }, + "devDependencies": { + "@directus/extensions-sdk": "11.0.2", + "vue": "^3.4.0" + } +} diff --git a/directus/extensions/acquisition/package.json b/directus/extensions/acquisition/package.json new file mode 100644 index 0000000..4bbaa84 --- /dev/null +++ b/directus/extensions/acquisition/package.json @@ -0,0 +1,27 @@ +{ + "name": "acquisition", + "version": "1.7.12", + "type": "module", + "directus:extension": { + "type": "endpoint", + "path": "dist/index.js", + "source": "src/index.ts", + "host": "^11.0.0" + }, + "scripts": { + "build": "node build.mjs", + "dev": "node build.mjs --watch" + }, + "devDependencies": { + "@directus/extensions-sdk": "11.0.2", + "@mintel/acquisition": "workspace:*", + "@mintel/mail": "workspace:*", + "esbuild": "^0.25.0", + "typescript": "^5.6.3" + }, + "dependencies": { + "jquery": "^3.7.1", + "react": "^19.2.4", + "react-dom": "^19.2.4" + } +} \ No newline at end of file diff --git a/directus/extensions/customer-manager/index.js b/directus/extensions/customer-manager/index.js new file mode 100644 index 0000000..8ac8e9c --- /dev/null +++ b/directus/extensions/customer-manager/index.js @@ -0,0 +1 @@ +import{useApi as e,defineModule as a}from"@directus/extensions-sdk";import{defineComponent as t,ref as l,onMounted as n,resolveComponent as i,resolveDirective as s,openBlock as d,createBlock as r,withCtx as u,createVNode as o,createElementBlock as m,Fragment as c,renderList as v,createTextVNode as p,toDisplayString as f,createCommentVNode as g,createElementVNode as y,withDirectives as b,nextTick as _}from"vue";const h={class:"content-wrapper"},x={key:0,class:"empty-state"},w={class:"header"},k={class:"header-left"},V={class:"title"},C={class:"subtitle"},M={class:"header-right"},F={class:"user-cell"},N={class:"user-name"},z={key:0,class:"status-date"},E={key:0,class:"drawer-content"},U={class:"form-section"},S={class:"field"},A={class:"drawer-actions"},T={key:0,class:"drawer-content"},Z={class:"form-section"},j={class:"field"},$={class:"field"},D={class:"field"},O={key:1,class:"field"},W={class:"drawer-actions"};var q=t({__name:"module",setup(a){const t=e(),q=l([]),B=l(null),K=l([]),L=l(!1),P=l(!1),G=l(null),I=l(null),H=l(!1),J=l(!1),Q=l({id:"",name:""}),R=l(!1),X=l(!1),Y=l({id:"",first_name:"",last_name:"",email:"",temporary_password:""}),ee=[{text:"Name",value:"name",sortable:!0},{text:"E-Mail",value:"email",sortable:!0},{text:"Zuletzt eingeladen",value:"last_invited",sortable:!0}];async function ae(){const e=await t.get("/items/companies",{params:{fields:["id","name"],sort:"name"}});q.value=e.data.data}async function te(e){B.value=e,L.value=!0;try{const a=await t.get("/items/client_users",{params:{filter:{company:{_eq:e.id}},fields:["*"],sort:"first_name"}});K.value=a.data.data}finally{L.value=!1}}function le(){J.value=!1,Q.value={id:"",name:""},H.value=!0}async function ne(){B.value&&(Q.value={id:B.value.id,name:B.value.name},J.value=!0,await _(),H.value=!0)}async function ie(){var e;if(Q.value.name){P.value=!0;try{J.value?(await t.patch(`/items/companies/${Q.value.id}`,{name:Q.value.name}),I.value={type:"success",message:"Firma aktualisiert!"}):(await t.post("/items/companies",{name:Q.value.name}),I.value={type:"success",message:"Firma angelegt!"}),H.value=!1,await ae(),(null==(e=B.value)?void 0:e.id)===Q.value.id&&(B.value.name=Q.value.name)}catch(e){I.value={type:"danger",message:e.message}}finally{P.value=!1}}}function se(){X.value=!1,Y.value={id:"",first_name:"",last_name:"",email:"",temporary_password:""},R.value=!0}async function de(){if(Y.value.email&&B.value){P.value=!0;try{X.value?(await t.patch(`/items/client_users/${Y.value.id}`,{first_name:Y.value.first_name,last_name:Y.value.last_name,email:Y.value.email}),I.value={type:"success",message:"Mitarbeiter aktualisiert!"}):(await t.post("/items/client_users",{first_name:Y.value.first_name,last_name:Y.value.last_name,email:Y.value.email,company:B.value.id}),I.value={type:"success",message:"Mitarbeiter angelegt!"}),R.value=!1,await te(B.value)}catch(e){I.value={type:"danger",message:e.message}}finally{P.value=!1}}}function re(e){const a=(null==e?void 0:e.item)||e;a&&a.id&&async function(e){Y.value={id:e.id||"",first_name:e.first_name||"",last_name:e.last_name||"",email:e.email||"",temporary_password:e.temporary_password||""},X.value=!0,await _(),R.value=!0}(a)}return n(()=>{ae()}),(e,a)=>{const l=i("v-icon"),n=i("v-list-item-icon"),_=i("v-text-overflow"),ae=i("v-list-item-content"),ue=i("v-list-item"),oe=i("v-divider"),me=i("v-list"),ce=i("v-notice"),ve=i("v-button"),pe=i("v-info"),fe=i("v-avatar"),ge=i("v-chip"),ye=i("v-table"),be=i("v-input"),_e=i("v-drawer"),he=i("private-view"),xe=s("tooltip");return d(),r(he,{title:"Customer Manager"},{navigation:u(()=>[o(me,{nav:""},{default:u(()=>[o(ue,{onClick:le,clickable:""},{default:u(()=>[o(n,null,{default:u(()=>[o(l,{name:"add",color:"var(--theme--primary)"})]),_:1}),o(ae,null,{default:u(()=>[o(_,{text:"Neue Firma anlegen"})]),_:1})]),_:1}),o(oe),(d(!0),m(c,null,v(q.value,e=>{var a;return d(),r(ue,{key:e.id,active:(null==(a=B.value)?void 0:a.id)===e.id,class:"company-item",clickable:"",onClick:a=>te(e)},{default:u(()=>[o(n,null,{default:u(()=>[o(l,{name:"business"})]),_:1}),o(ae,null,{default:u(()=>[o(_,{text:e.name},null,8,["text"])]),_:2},1024)]),_:2},1032,["active","onClick"])}),128))]),_:1})]),"title-outer:after":u(()=>[I.value?(d(),r(ce,{key:0,type:I.value.type,onClose:a[0]||(a[0]=e=>I.value=null),dismissible:""},{default:u(()=>[p(f(I.value.message),1)]),_:1},8,["type"])):g("v-if",!0)]),default:u(()=>[y("div",h,[B.value?(d(),m(c,{key:1},[y("header",w,[y("div",k,[y("h1",V,f(B.value.name),1),y("p",C,f(K.value.length)+" Kunden-Mitarbeiter",1)]),y("div",M,[b((d(),r(ve,{secondary:"",rounded:"",icon:"",onClick:ne},{default:u(()=>[o(l,{name:"edit"})]),_:1})),[[xe,"Firma bearbeiten",void 0,{bottom:!0}]]),o(ve,{primary:"",onClick:se},{default:u(()=>[...a[14]||(a[14]=[p(" Mitarbeiter hinzufügen ",-1)])]),_:1})])]),o(ye,{headers:ee,items:K.value,loading:L.value,class:"clickable-table","fixed-header":"","onClick:row":re},{"item.name":u(({item:e})=>[y("div",F,[o(fe,{name:e.first_name,"x-small":""},null,8,["name"]),y("span",N,f(e.first_name)+" "+f(e.last_name),1)])]),"item.last_invited":u(({item:e})=>{return[e.last_invited?(d(),m("span",z,f((t=e.last_invited,new Date(t).toLocaleString("de-DE",{day:"2-digit",month:"2-digit",year:"numeric",hour:"2-digit",minute:"2-digit"}))),1)):(d(),r(ge,{key:1,"x-small":""},{default:u(()=>[...a[15]||(a[15]=[p("Noch nie",-1)])]),_:1}))];var t}),_:2},1032,["items","loading"])],64)):(d(),m("div",x,[o(pe,{title:"Firmen auswählen",icon:"business",center:""},{default:u(()=>[a[12]||(a[12]=p(" Wähle eine Firma in der Navigation aus oder ",-1)),o(ve,{"x-small":"",onClick:le},{default:u(()=>[...a[11]||(a[11]=[p("erstelle eine neue Firma",-1)])]),_:1}),a[13]||(a[13]=p(". ",-1))]),_:1})]))]),o(_e,{modelValue:H.value,"onUpdate:modelValue":a[2]||(a[2]=e=>H.value=e),title:J.value?"Firma bearbeiten":"Neue Firma anlegen",icon:"business",onCancel:a[3]||(a[3]=e=>H.value=!1)},{default:u(()=>[H.value?(d(),m("div",E,[y("div",U,[y("div",S,[a[16]||(a[16]=y("span",{class:"label"},"Firmenname",-1)),o(be,{modelValue:Q.value.name,"onUpdate:modelValue":a[1]||(a[1]=e=>Q.value.name=e),placeholder:"z.B. KLZ Cables",autofocus:""},null,8,["modelValue"])])]),y("div",A,[o(ve,{primary:"",block:"",loading:P.value,onClick:ie},{default:u(()=>[...a[17]||(a[17]=[p("Speichern",-1)])]),_:1},8,["loading"])])])):g("v-if",!0)]),_:1},8,["modelValue","title"]),o(_e,{modelValue:R.value,"onUpdate:modelValue":a[9]||(a[9]=e=>R.value=e),title:X.value?"Mitarbeiter bearbeiten":"Neuen Mitarbeiter anlegen",icon:"person",onCancel:a[10]||(a[10]=e=>R.value=!1)},{default:u(()=>[R.value?(d(),m("div",T,[y("div",Z,[y("div",j,[a[18]||(a[18]=y("span",{class:"label"},"Vorname",-1)),o(be,{modelValue:Y.value.first_name,"onUpdate:modelValue":a[4]||(a[4]=e=>Y.value.first_name=e),placeholder:"Vorname",autofocus:""},null,8,["modelValue"])]),y("div",$,[a[19]||(a[19]=y("span",{class:"label"},"Nachname",-1)),o(be,{modelValue:Y.value.last_name,"onUpdate:modelValue":a[5]||(a[5]=e=>Y.value.last_name=e),placeholder:"Nachname"},null,8,["modelValue"])]),y("div",D,[a[20]||(a[20]=y("span",{class:"label"},"E-Mail",-1)),o(be,{modelValue:Y.value.email,"onUpdate:modelValue":a[6]||(a[6]=e=>Y.value.email=e),placeholder:"E-Mail Adresse",type:"email"},null,8,["modelValue"])]),X.value?(d(),r(oe,{key:0})):g("v-if",!0),X.value?(d(),m("div",O,[a[21]||(a[21]=y("span",{class:"label"},"Temporäres Passwort",-1)),o(be,{modelValue:Y.value.temporary_password,"onUpdate:modelValue":a[7]||(a[7]=e=>Y.value.temporary_password=e),readonly:"",class:"password-input"},null,8,["modelValue"]),a[22]||(a[22]=y("p",{class:"field-note"},"Wird beim Senden der Zugangsdaten automatisch generiert.",-1))])):g("v-if",!0)]),y("div",W,[o(ve,{primary:"",block:"",loading:P.value,onClick:de},{default:u(()=>[...a[23]||(a[23]=[p("Daten speichern",-1)])]),_:1},8,["loading"]),X.value?(d(),m(c,{key:0},[o(oe),b((d(),r(ve,{secondary:"",block:"",loading:G.value===Y.value.id,onClick:a[8]||(a[8]=e=>async function(e){G.value=e.id;try{if(await t.post("/flows/trigger/33443f6b-cec7-4668-9607-f33ea674d501",[e.id]),I.value={type:"success",message:`Zugangsdaten für ${e.first_name} versendet. 📧`},await te(B.value),R.value&&Y.value.id===e.id){const a=K.value.find(a=>a.id===e.id);a&&(Y.value.temporary_password=a.temporary_password)}}catch(e){I.value={type:"danger",message:`Fehler: ${e.message}`}}finally{G.value=null}}(Y.value))},{default:u(()=>[o(l,{name:"send",left:""}),a[24]||(a[24]=p(" Zugangsdaten senden ",-1))]),_:1},8,["loading"])),[[xe,"Generiert PW, speichert es und sendet E-Mail",void 0,{bottom:!0}]])],64)):g("v-if",!0)])])):g("v-if",!0)]),_:1},8,["modelValue","title"])]),_:1})}}}),B=[],K=[];!function(e,a){if(e&&"undefined"!=typeof document){var t,l=!0===a.prepend?"prepend":"append",n=!0===a.singleTag,i="string"==typeof a.container?document.querySelector(a.container):document.getElementsByTagName("head")[0];if(n){var s=B.indexOf(i);-1===s&&(s=B.push(i)-1,K[s]={}),t=K[s]&&K[s][l]?K[s][l]:K[s][l]=d()}else t=d();65279===e.charCodeAt(0)&&(e=e.substring(1)),t.styleSheet?t.styleSheet.cssText+=e:t.appendChild(document.createTextNode(e))}function d(){var e=document.createElement("style");if(e.setAttribute("type","text/css"),a.attributes)for(var t=Object.keys(a.attributes),n=0;n{const t=e.__vccOpts||e;for(const[e,l]of a)t[e]=l;return t})(q,[["__scopeId","data-v-3fd11e72"],["__file","module.vue"]])}]});export{L as default}; diff --git a/directus/extensions/customer-manager/package.json b/directus/extensions/customer-manager/package.json new file mode 100644 index 0000000..426752b --- /dev/null +++ b/directus/extensions/customer-manager/package.json @@ -0,0 +1,30 @@ +{ + "name": "customer-manager", + "description": "Custom High-Fidelity Customer & Company Management for Directus", + "icon": "supervisor_account", + "version": "1.7.12", + "type": "module", + "keywords": [ + "directus", + "directus-extension", + "directus-extension-module" + ], + "files": [ + "dist" + ], + "directus:extension": { + "type": "module", + "path": "index.js", + "source": "src/index.ts", + "host": "*", + "name": "Customer Manager" + }, + "scripts": { + "build": "directus-extension build && (cp -f dist/index.js index.js 2>/dev/null || true)", + "dev": "directus-extension build -w" + }, + "devDependencies": { + "@directus/extensions-sdk": "11.0.2", + "vue": "^3.4.0" + } +} diff --git a/directus/extensions/feedback-commander/index.js b/directus/extensions/feedback-commander/index.js new file mode 100644 index 0000000..f28e389 --- /dev/null +++ b/directus/extensions/feedback-commander/index.js @@ -0,0 +1 @@ +import{useApi as e,defineModule as a}from"@directus/extensions-sdk";import{defineComponent as t,ref as n,computed as l,onMounted as r,resolveComponent as o,openBlock as d,createBlock as s,withCtx as i,createVNode as c,createTextVNode as u,toDisplayString as p,createElementVNode as v,createElementBlock as b,Fragment as m,renderList as f,createCommentVNode as x,TransitionGroup as g,normalizeClass as h,normalizeStyle as y,Transition as k}from"vue";const _={class:"sidebar-header"},w={class:"feedback-container"},C={key:0,class:"empty-state"},j={key:1,class:"empty-state"},S={key:2,class:"operational-layout"},z={class:"triage-lane"},F={class:"lane-header"},A={class:"lane-content scrollbar"},E=["onClick"],T={class:"card-body"},V={class:"card-header"},D={class:"card-user"},P={class:"card-date"},L={class:"card-text"},O={class:"card-footer"},I={class:"meta-tags"},R={class:"processing-desk scrollbar"},U={class:"desk-header"},M={class:"headline-group"},Y={class:"status-indicator"},q={class:"status-text"},B={class:"header-actions"},N={class:"desk-grid"},H={class:"main-column"},W={key:0,class:"visual-proof"},X={class:"proof-label"},$=["src"],G={class:"main-text"},J={class:"reply-section"},K={class:"section-divider"},Q={class:"thread"},Z={class:"reply-header"},ee={class:"reply-user"},ae={class:"reply-date"},te={class:"reply-text"},ne={key:0,class:"empty-state-mini"},le={class:"composer"},re={class:"composer-actions"},oe={class:"meta-column"},de={class:"meta-item"},se={class:"meta-item"},ie=["title"],ce={class:"meta-item"},ue={class:"trace-code"},pe={class:"meta-item"},ve={class:"coords"},be={class:"meta-item"},me={class:"id-code"},fe={class:"help-box"},xe={key:1,class:"no-selection-desk"};var ge=t({__name:"module",setup(a){const t=e(),ge=n([]),he=n([]),ye=n(!0),ke=n(null),_e=n(!1),we=n(null),Ce=n("all"),je=n("open"),Se=n(""),ze=[{text:"Open",value:"open",icon:"warning",color:"#E91E63"},{text:"In Progress",value:"in_progress",icon:"play_arrow",color:"#2196F3"},{text:"Resolved",value:"resolved",icon:"check_circle",color:"#4CAF50"}],Fe=[{text:"All Statuses",value:"all"},...ze],Ae=l(()=>{const e=new Set(ge.value.map(e=>e.project).filter(Boolean));return Array.from(e).sort()}),Ee=l(()=>ge.value.filter(e=>{const a="all"===Ce.value||e.project===Ce.value,t=e.status||"open",n="all"===je.value||t===je.value;return a&&n}));async function Te(){ye.value=!0,ke.value=null;try{const e=await t.get("/items/visual_feedback",{params:{sort:"-date_created,-id",limit:300}});ge.value=e.data.data}catch(e){ke.value=e.message}finally{ye.value=!1}}async function Ve(e){if(we.value)try{await t.patch(`/items/visual_feedback/${we.value.id}`,{status:e}),Te()}catch(e){console.error(e)}}async function De(){if(Se.value.trim()&&we.value){_e.value=!0;try{const e=await t.post("/items/visual_feedback_comments",{feedback_id:we.value.id,user_name:"Operator",text:Se.value});he.value.unshift(e.data.data),Se.value=""}catch(e){console.error(e)}finally{_e.value=!1}}}function Pe(e){return e&&"number"!=typeof e?new Date(e).toLocaleDateString()+" "+new Date(e).toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"}):"Legacy"}function Le(e){const a=function(e){if(!e||!e.url)return"";try{const a=new URL(e.url);return a.searchParams.set("fb_id",e.id),a.toString()}catch(a){return e.url+"?fb_id="+e.id}}(e);a&&window.open(a,"_blank")}function Oe(e){const a=ze.find(a=>a.value===e);return a?a.color:"var(--foreground-subdued)"}return r(()=>{Te()}),(e,a)=>{const n=o("v-breadcrumb"),l=o("v-chip"),r=o("v-text-overflow"),Ie=o("v-icon"),Re=o("v-list-item-icon"),Ue=o("v-list-item-content"),Me=o("v-list-item"),Ye=o("v-list"),qe=o("v-info"),Be=o("v-button"),Ne=o("v-select"),He=o("v-card-title"),We=o("v-card-text"),Xe=o("v-card"),$e=o("v-divider"),Ge=o("v-textarea"),Je=o("private-view");return d(),s(Je,{title:"Feedback Commander"},{headline:i(()=>[c(n,{items:[{name:"Feedback",to:"/feedback-commander"}]})]),"title-outer:after":i(()=>[ye.value?(d(),s(l,{key:0,label:"",color:"blue",small:""},{default:i(()=>[...a[6]||(a[6]=[u("Loading...",-1)])]),_:1})):ke.value?(d(),s(l,{key:1,label:"",color:"red",small:""},{default:i(()=>[...a[7]||(a[7]=[u("Fetch Error",-1)])]),_:1})):(d(),s(l,{key:2,label:"",color:"green",small:""},{default:i(()=>[u(p(ge.value.length)+" Items",1)]),_:1}))]),navigation:i(()=>[v("div",_,[c(r,{text:"Websites",class:"header-text"})]),c(Ye,{nav:""},{default:i(()=>[c(Me,{active:"all"===Ce.value,onClick:a[0]||(a[0]=e=>Ce.value="all"),clickable:""},{default:i(()=>[c(Re,null,{default:i(()=>[c(Ie,{name:"language"})]),_:1}),c(Ue,null,{default:i(()=>[c(r,{text:"All Projects"})]),_:1})]),_:1},8,["active"]),(d(!0),b(m,null,f(Ae.value,e=>(d(),s(Me,{key:e,active:Ce.value===e,onClick:a=>Ce.value=e,clickable:""},{default:i(()=>[c(Re,null,{default:i(()=>[c(Ie,{name:"public",color:"var(--primary)"})]),_:1}),c(Ue,null,{default:i(()=>[c(r,{text:e||"Unknown"},null,8,["text"])]),_:2},1024)]),_:2},1032,["active","onClick"]))),128))]),_:1})]),default:i(()=>[v("div",w,[ge.value.length||ye.value||ke.value?x("v-if",!0):(d(),b("div",C,[c(qe,{icon:"inbox",title:"Clean Inbox",center:""},{default:i(()=>[...a[8]||(a[8]=[u(" All feedback has been processed. Great job! ",-1)])]),_:1})])),ke.value?(d(),b("div",j,[c(qe,{icon:"error",title:"Fetch Failed",description:ke.value,center:""},null,8,["description"]),c(Be,{onClick:Te,secondary:"",small:""},{default:i(()=>[...a[9]||(a[9]=[u("Retry",-1)])]),_:1})])):ge.value.length?(d(),b("div",S,[x(" Detailed Triage Lane "),v("aside",z,[v("div",F,[c(Ne,{modelValue:je.value,"onUpdate:modelValue":a[1]||(a[1]=e=>je.value=e),items:Fe,small:"",placeholder:"Status Filter"},null,8,["modelValue"])]),v("div",A,[c(g,{name:"list"},{default:i(()=>[(d(!0),b(m,null,f(Ee.value,e=>{var a,n;return d(),b("div",{key:e.id,class:h(["feedback-card",{active:(null==(a=we.value)?void 0:a.id)===e.id}]),onClick:a=>async function(e){we.value=null,setTimeout(async()=>{we.value=e,he.value=[];try{const a=await t.get("/items/visual_feedback_comments",{params:{filter:{feedback_id:{_eq:e.id}},sort:"-date_created,-id"}});he.value=a.data.data}catch(e){console.error(e)}},10)}(e)},[v("div",{class:"card-status-bar",style:y({background:Oe(e.status||"open")})},null,4),v("div",T,[v("header",V,[v("span",D,p(e.user_name),1),v("span",P,p(Pe(e.date_created||e.id)),1)]),v("div",L,p(e.text),1),v("footer",O,[v("div",I,[c(l,{"x-small":"",outline:""},{default:i(()=>[u(p(e.project),1)]),_:2},1024),c(Ie,{name:"bug"===e.type?"bug_report":"lightbulb",color:"bug"===e.type?"#E91E63":"#FFC107",small:""},null,8,["name","color"])]),(null==(n=we.value)?void 0:n.id)===e.id?(d(),s(Ie,{key:0,name:"chevron_right",small:""})):x("v-if",!0)])])],10,E)}),128))]),_:1})])]),x(" Elaborated Master-Detail Desk "),v("main",R,[c(k,{name:"fade",mode:"out-in"},{default:i(()=>{return[we.value?(d(),b("div",{key:we.value.id,class:"desk-content"},[v("header",U,[v("div",M,[v("div",Y,[v("div",{class:"status-dot",style:y({background:Oe(we.value.status||"open")})},null,4),v("span",q,p((e=we.value.status||"open",e.charAt(0).toUpperCase()+e.slice(1).replace("_"," "))),1)]),v("h2",null,p(we.value.user_name)+"'s Submission",1)]),v("div",B,[c(Be,{primary:"",onClick:a[2]||(a[2]=e=>Le(we.value))},{default:i(()=>[c(Ie,{name:"open_in_new",left:""}),a[10]||(a[10]=u(" Open & Highlight ",-1))]),_:1}),c(Ne,{modelValue:we.value.status,"onUpdate:modelValue":[a[3]||(a[3]=e=>we.value.status=e),Ve],items:ze,inline:""},null,8,["modelValue"])])]),v("div",N,[x(" Message Container "),v("div",H,[c(Xe,{class:"content-card"},{default:i(()=>[c(He,null,{default:i(()=>[c(Ie,{name:"format_quote",left:""}),a[11]||(a[11]=u(" Feedback Content ",-1))]),_:1}),c(We,{class:"feedback-body"},{default:i(()=>{return[we.value.screenshot?(d(),b("div",W,[v("label",X,[c(Ie,{name:"photo","x-small":""}),a[12]||(a[12]=u(" Element Snapshot",-1))]),v("img",{src:(e=we.value.screenshot,e?`/assets/${e}`:""),class:"screenshot-img"},null,8,$)])):x("v-if",!0),v("div",G,p(we.value.text),1)];var e}),_:1})]),_:1}),v("section",J,[v("div",K,[c($e),a[13]||(a[13]=v("span",{class:"divider-label"},"Internal Communication",-1)),c($e)]),v("div",Q,[c(g,{name:"thread-list"},{default:i(()=>[(d(!0),b(m,null,f(he.value,e=>(d(),b("div",{key:e.id,class:"reply-bubble"},[v("header",Z,[v("span",ee,p(e.user_name),1),v("span",ae,p(Pe(e.date_created||e.id)),1)]),v("div",te,p(e.text),1)]))),128))]),_:1}),he.value.length?x("v-if",!0):(d(),b("div",ne,[c(Ie,{name:"auto_awesome",small:""}),a[14]||(a[14]=u(" No replies yet. Start the thread. ",-1))]))]),v("div",le,[c(Ge,{modelValue:Se.value,"onUpdate:modelValue":a[4]||(a[4]=e=>Se.value=e),placeholder:"Compose internal response...","auto-grow":""},null,8,["modelValue"]),v("div",re,[c(Be,{secondary:"",loading:_e.value,onClick:De},{default:i(()=>[...a[15]||(a[15]=[u("Post Reply",-1)])]),_:1},8,["loading"])])])])]),x(" Technical Sidebar "),v("aside",oe,[c(Xe,{class:"meta-card"},{default:i(()=>[c(He,null,{default:i(()=>[...a[16]||(a[16]=[u("Context",-1)])]),_:1}),c(We,{class:"meta-list"},{default:i(()=>{return[v("div",de,[v("label",null,[c(Ie,{name:"public","x-small":""}),a[17]||(a[17]=u(" Website",-1))]),v("strong",null,p(we.value.project),1)]),v("div",se,[v("label",null,[c(Ie,{name:"link","x-small":""}),a[18]||(a[18]=u(" Source Path",-1))]),v("span",{class:"truncate-path",title:we.value.url},p((e=we.value.url,e?e.replace(/^https?:\/\//,""):"")),9,ie),c(Be,{icon:"",small:"",onClick:a[5]||(a[5]=e=>function(e){e&&window.open(e,"_blank")}(we.value.url))},{default:i(()=>[c(Ie,{name:"launch"})]),_:1})]),c($e),v("div",ce,[v("label",null,[c(Ie,{name:"layers","x-small":""}),a[19]||(a[19]=u(" Element Trace",-1))]),v("code",ue,p(we.value.selector||"Body"),1)]),v("div",pe,[v("label",null,[c(Ie,{name:"location_searching","x-small":""}),a[20]||(a[20]=u(" Precise Mark",-1))]),v("span",ve,"X: "+p(Math.round(we.value.x))+"px / Y: "+p(Math.round(we.value.y))+"px",1)]),v("div",be,[v("label",null,[c(Ie,{name:"fingerprint","x-small":""}),a[21]||(a[21]=u(" Reference ID",-1))]),v("code",me,p(we.value.id),1)])];var e}),_:1})]),_:1}),v("div",fe,[c(Ie,{name:"help_outline","x-small":""}),a[22]||(a[22]=v("span",null,'Click "Open & Highlight" to jump directly to this element on the live site.',-1))])])])])):(d(),b("div",xe,[c(qe,{icon:"touch_app",title:"Select Feedback",center:""},{default:i(()=>[...a[23]||(a[23]=[u(" Choose an entry from the triage list to view details and process. ",-1)])]),_:1})]))];var e}),_:1})])])):x("v-if",!0)])]),_:1})}}}),he=[],ye=[];!function(e,a){if(e&&"undefined"!=typeof document){var t,n=!0===a.prepend?"prepend":"append",l=!0===a.singleTag,r="string"==typeof a.container?document.querySelector(a.container):document.getElementsByTagName("head")[0];if(l){var o=he.indexOf(r);-1===o&&(o=he.push(r)-1,ye[o]={}),t=ye[o]&&ye[o][n]?ye[o][n]:ye[o][n]=d()}else t=d();65279===e.charCodeAt(0)&&(e=e.substring(1)),t.styleSheet?t.styleSheet.cssText+=e:t.appendChild(document.createTextNode(e))}function d(){var e=document.createElement("style");if(e.setAttribute("type","text/css"),a.attributes)for(var t=Object.keys(a.attributes),l=0;l{const t=e.__vccOpts||e;for(const[e,n]of a)t[e]=n;return t})(ge,[["__scopeId","data-v-409b935e"],["__file","module.vue"]])}]});export{ke as default}; diff --git a/directus/extensions/feedback-commander/package.json b/directus/extensions/feedback-commander/package.json new file mode 100644 index 0000000..a0e6798 --- /dev/null +++ b/directus/extensions/feedback-commander/package.json @@ -0,0 +1,30 @@ +{ + "name": "feedback-commander", + "description": "Custom High-Fidelity Feedback Management Extension for Directus", + "icon": "view_kanban", + "version": "1.7.12", + "type": "module", + "keywords": [ + "directus", + "directus-extension", + "directus-extension-module" + ], + "files": [ + "dist" + ], + "directus:extension": { + "type": "module", + "path": "index.js", + "source": "src/index.ts", + "host": "*", + "name": "Feedback Commander" + }, + "scripts": { + "build": "directus-extension build && (cp -f dist/index.js index.js 2>/dev/null || true)", + "dev": "directus-extension build -w" + }, + "devDependencies": { + "@directus/extensions-sdk": "11.0.2", + "vue": "^3.4.0" + } +} diff --git a/directus/extensions/people-manager/index.js b/directus/extensions/people-manager/index.js new file mode 100644 index 0000000..7b71123 --- /dev/null +++ b/directus/extensions/people-manager/index.js @@ -0,0 +1 @@ +import{useApi as e,defineModule as a}from"@directus/extensions-sdk";import{defineComponent as t,ref as l,onMounted as n,resolveComponent as i,resolveDirective as s,openBlock as d,createBlock as o,withCtx as r,createVNode as u,createElementBlock as c,Fragment as p,renderList as v,createElementVNode as m,createTextVNode as f,toDisplayString as b,createCommentVNode as g,withDirectives as y}from"vue";var h=Object.defineProperty,x=Object.getOwnPropertySymbols,_=Object.prototype.hasOwnProperty,w=Object.prototype.propertyIsEnumerable,V=(e,a,t)=>a in e?h(e,a,{enumerable:!0,configurable:!0,writable:!0,value:t}):e[a]=t;const k={class:"content-wrapper"},P={key:1,class:"empty-state"},C={key:2},O={class:"header"},j={class:"header-left"},N={class:"title"},E={class:"subtitle"},T={class:"header-right"},U={class:"details-grid"},z={class:"detail-item"},M={class:"value"},S={class:"detail-item"},A={class:"value"},$={class:"drawer-content"},B={class:"form-section"},F={class:"field"},I={class:"field"},q={class:"field"},K={class:"field"},W={class:"field"},D={class:"drawer-actions"};var G=t({__name:"module",setup(a){const t=e(),h=l([]),G=l(null),H=l(null),J=l(!1),L=l(!1),Q=l(!1),R=l({id:null,first_name:"",last_name:"",email:"",company:"",phone:""});async function X(){try{const e=await t.get("/items/people",{params:{sort:"last_name"}});h.ref=e.data.data}catch(e){console.error("Failed to fetch people:",e)}}function Y(){Q.value=!1,R.value={id:null,first_name:"",last_name:"",email:"",company:"",phone:""},L.value=!0}function Z(){Q.value=!0,R.value=((e,a)=>{for(var t in a||(a={}))_.call(a,t)&&V(e,t,a[t]);if(x)for(var t of x(a))w.call(a,t)&&V(e,t,a[t]);return e})({},G.value),L.value=!0}async function ee(){if(R.value.first_name&&R.value.last_name){J.value=!0;try{Q.value?(await t.patch(`/items/people/${R.value.id}`,R.value),H.value={type:"success",message:"Person aktualisiert!"}):(await t.post("/items/people",R.value),H.value={type:"success",message:"Person angelegt!"}),L.value=!1,await X(),Q.value&&(G.value=R.value)}catch(e){H.value={type:"danger",message:e.message}}finally{J.value=!1}}else H.value={type:"danger",message:"Vor- und Nachname sind erforderlich."}}async function ae(){if(confirm("Soll diese Person wirklich gelöscht werden?"))try{await t.delete(`/items/people/${G.value.id}`),H.value={type:"success",message:"Person gelöscht."},G.value=null,await X()}catch(e){H.value={type:"danger",message:e.message}}}return n(X),(e,a)=>{const t=i("v-icon"),l=i("v-list-item-icon"),n=i("v-text-overflow"),x=i("v-list-item-content"),_=i("v-list-item"),w=i("v-divider"),V=i("v-list"),X=i("v-notice"),te=i("v-button"),le=i("v-info"),ne=i("v-input"),ie=i("v-drawer"),se=i("private-view"),de=s("tooltip");return d(),o(se,{title:"People Manager"},{navigation:r(()=>[u(V,{nav:""},{default:r(()=>[u(_,{onClick:Y,clickable:""},{default:r(()=>[u(l,null,{default:r(()=>[u(t,{name:"add",color:"var(--theme--primary)"})]),_:1}),u(x,null,{default:r(()=>[u(n,{text:"Neue Person anlegen"})]),_:1})]),_:1}),u(w),(d(!0),c(p,null,v(h.value,e=>{var a;return d(),o(_,{key:e.id,active:(null==(a=G.value)?void 0:a.id)===e.id,class:"person-item",clickable:"",onClick:a=>function(e){G.value=e}(e)},{default:r(()=>[u(l,null,{default:r(()=>[u(t,{name:"person"})]),_:1}),u(x,null,{default:r(()=>[u(n,{text:`${e.first_name} ${e.last_name}`},null,8,["text"])]),_:2},1024)]),_:2},1032,["active","onClick"])}),128))]),_:1})]),default:r(()=>[m("div",k,[H.value?(d(),o(X,{key:0,type:H.value.type,onClose:a[0]||(a[0]=e=>H.value=null),dismissible:""},{default:r(()=>[f(b(H.value.message),1)]),_:1},8,["type"])):g("v-if",!0),G.value?(d(),c("div",C,[m("header",O,[m("div",j,[m("h1",N,b(G.value.first_name)+" "+b(G.value.last_name),1),m("p",E,b(G.value.email||"Keine E-Mail angegeben"),1)]),m("div",T,[y((d(),o(te,{secondary:"",rounded:"",icon:"",onClick:Z},{default:r(()=>[u(t,{name:"edit"})]),_:1})),[[de,"Person bearbeiten"]]),y((d(),o(te,{danger:"",rounded:"",icon:"",onClick:ae},{default:r(()=>[u(t,{name:"delete"})]),_:1})),[[de,"Person löschen"]])])]),u(w),m("div",U,[m("div",z,[a[11]||(a[11]=m("span",{class:"label"},"Organisation",-1)),m("p",M,b(G.value.company||"---"),1)]),m("div",S,[a[12]||(a[12]=m("span",{class:"label"},"Telefon",-1)),m("p",A,b(G.value.phone||"---"),1)])])])):(d(),c("div",P,[u(le,{title:"Person auswählen",icon:"person",center:""},{default:r(()=>[a[9]||(a[9]=f(" Wähle eine Person in der Navigation aus oder ",-1)),u(te,{"x-small":"",onClick:Y},{default:r(()=>[...a[8]||(a[8]=[f("erstelle eine neue Person",-1)])]),_:1}),a[10]||(a[10]=f(". ",-1))]),_:1})]))]),u(ie,{modelValue:L.value,"onUpdate:modelValue":a[6]||(a[6]=e=>L.value=e),title:Q.value?"Person bearbeiten":"Neue Person anlegen",icon:"person",onCancel:a[7]||(a[7]=e=>L.value=!1)},{default:r(()=>[m("div",$,[m("div",B,[m("div",F,[a[13]||(a[13]=m("span",{class:"label"},"Vorname",-1)),u(ne,{modelValue:R.value.first_name,"onUpdate:modelValue":a[1]||(a[1]=e=>R.value.first_name=e),placeholder:"Vorname",autofocus:""},null,8,["modelValue"])]),m("div",I,[a[14]||(a[14]=m("span",{class:"label"},"Nachname",-1)),u(ne,{modelValue:R.value.last_name,"onUpdate:modelValue":a[2]||(a[2]=e=>R.value.last_name=e),placeholder:"Nachname"},null,8,["modelValue"])]),m("div",q,[a[15]||(a[15]=m("span",{class:"label"},"E-Mail",-1)),u(ne,{modelValue:R.value.email,"onUpdate:modelValue":a[3]||(a[3]=e=>R.value.email=e),placeholder:"email@beispiel.de",type:"email"},null,8,["modelValue"])]),m("div",K,[a[16]||(a[16]=m("span",{class:"label"},"Organisation / Firma",-1)),u(ne,{modelValue:R.value.company,"onUpdate:modelValue":a[4]||(a[4]=e=>R.value.company=e),placeholder:"z.B. Mintel"},null,8,["modelValue"])]),m("div",W,[a[17]||(a[17]=m("span",{class:"label"},"Telefon",-1)),u(ne,{modelValue:R.value.phone,"onUpdate:modelValue":a[5]||(a[5]=e=>R.value.phone=e),placeholder:"+49 ..."},null,8,["modelValue"])])]),m("div",D,[u(te,{primary:"",block:"",loading:J.value,onClick:ee},{default:r(()=>[...a[18]||(a[18]=[f(" Person speichern ",-1)])]),_:1},8,["loading"])])])]),_:1},8,["modelValue","title"])]),_:1})}}}),H=[],J=[];!function(e,a){if(e&&"undefined"!=typeof document){var t,l=!0===a.prepend?"prepend":"append",n=!0===a.singleTag,i="string"==typeof a.container?document.querySelector(a.container):document.getElementsByTagName("head")[0];if(n){var s=H.indexOf(i);-1===s&&(s=H.push(i)-1,J[s]={}),t=J[s]&&J[s][l]?J[s][l]:J[s][l]=d()}else t=d();65279===e.charCodeAt(0)&&(e=e.substring(1)),t.styleSheet?t.styleSheet.cssText+=e:t.appendChild(document.createTextNode(e))}function d(){var e=document.createElement("style");if(e.setAttribute("type","text/css"),a.attributes)for(var t=Object.keys(a.attributes),n=0;n{const t=e.__vccOpts||e;for(const[e,l]of a)t[e]=l;return t})(G,[["__scopeId","data-v-bd30dab7"],["__file","module.vue"]])}]});export{L as default}; diff --git a/directus/extensions/people-manager/package.json b/directus/extensions/people-manager/package.json new file mode 100644 index 0000000..8a02f79 --- /dev/null +++ b/directus/extensions/people-manager/package.json @@ -0,0 +1,30 @@ +{ + "name": "people-manager", + "description": "Custom High-Fidelity People Management for Directus", + "icon": "person", + "version": "1.7.12", + "type": "module", + "keywords": [ + "directus", + "directus-extension", + "directus-extension-module" + ], + "files": [ + "dist" + ], + "directus:extension": { + "type": "module", + "path": "index.js", + "source": "src/index.ts", + "host": "*", + "name": "People Manager" + }, + "scripts": { + "build": "directus-extension build && (cp -f dist/index.js index.js 2>/dev/null || true)", + "dev": "directus-extension build -w" + }, + "devDependencies": { + "@directus/extensions-sdk": "11.0.2", + "vue": "^3.4.0" + } +} diff --git a/directus/uploads/directus-health-file b/directus/uploads/directus-health-file new file mode 100644 index 0000000..3d1793f --- /dev/null +++ b/directus/uploads/directus-health-file @@ -0,0 +1 @@ +-Jy2r \ No newline at end of file diff --git a/packages/acquisition-library/build.mjs b/packages/acquisition-library/build.mjs index 2232e9e..1c16d32 100644 --- a/packages/acquisition-library/build.mjs +++ b/packages/acquisition-library/build.mjs @@ -22,7 +22,13 @@ build({ target: 'node18', outfile: outfile, format: 'esm', - external: ["jsdom", "jsdom/*", "jquery", "jquery/*", "canvas", "fs", "path", "os", "http", "https", "zlib", "stream", "util", "url", "net", "tls", "crypto"], + jsx: 'automatic', + loader: { + '.tsx': 'tsx', + '.ts': 'ts', + '.js': 'js', + }, + external: ["@react-pdf/renderer", "react", "react-dom", "jsdom", "jsdom/*", "jquery", "jquery/*", "canvas", "fs", "path", "os", "http", "https", "zlib", "stream", "util", "url", "net", "tls", "crypto"], plugins: [{ name: 'mock-canvas', setup(build) { diff --git a/packages/acquisition-library/src/components/pdf/modules/BrandingModules.tsx b/packages/acquisition-library/src/components/pdf/modules/BrandingModules.tsx new file mode 100644 index 0000000..daf007f --- /dev/null +++ b/packages/acquisition-library/src/components/pdf/modules/BrandingModules.tsx @@ -0,0 +1,218 @@ +"use client"; + +import * as React from "react"; +import { + View as PDFView, + Text as PDFText, + StyleSheet, +} from "@react-pdf/renderer"; +import { + DocumentTitle, + IndustrialListItem, + IndustrialCard, + Divider, + COLORS, + FONT_SIZES, +} from "../SharedUI"; + +const styles = StyleSheet.create({ + industrialTextLead: { + fontSize: FONT_SIZES.BODY, + color: COLORS.TEXT_MAIN, + lineHeight: 1.4, + marginBottom: 16, + }, + industrialText: { + fontSize: FONT_SIZES.BODY, + color: COLORS.TEXT_DIM, + lineHeight: 1.4, + marginBottom: 12, + }, + industrialGrid2: { flexDirection: "row" }, + industrialCol: { width: "46%" }, +}); + +export const AboutModule = () => ( + <> + + + + + + Begleitung mittelständischer Unternehmen und Agenturen bei der + Realisierung anspruchsvoller Web-Projekte. Als Senior Software Developer + mit over 15 Jahren Erfahrung wird das gesamte technische Spektrum + abgedeckt – von der Architektur bis zum fertigen Produkt. + + + + + + Erfahrung & Substanz + + + Der Werdegang umfasst alle Ebenen der Webentwicklung: von der + Teamleitung in Kreativagenturen bis zur Softwareentwicklung für + internationale Konzerne. + + + Die Kenntnis komplexer Enterprise-Systeme wird mit der Agilität + kombiniert, die im Mittelstand gefordert ist. Dieses Wissen + ermöglicht den Bau von Lösungen, die technologisch auf Augenhöhe mit + Konzern-Standards sind, jedoch ohne unnötigen bürokratischen + Overhead auskommen. + + + + + + Fokus Einzelentwicklung + + + Die Umsetzung erfolgt bewusst als spezialisierter Einzelentwickler. + Dies garantiert maximale Geschwindigkeit, direkte Kommunikationswege + und volle technologische Verantwortung. + + + Als direkter technischer Sparringspartner bleibt die Codebasis von + der ersten bis zur letzten Zeile transparent und wartbar. Diese + Unmittelbarkeit stellt sicher, dass Ergebnisse sowohl technisch + sauber als auch wirtschaftlich sinnvoll realisiert werden. + + + + + + + Infrastruktur & Souveränität + + + Es wird keine instabile Prototyp-Software geliefert, sondern + produktionsreife Systeme, die technisch skalierbar bleiben. Die + Codebasis folgt modernen Standards – bei wachsenden Ansprüchen oder + dem Wechsel zu einer Agentur kann der Quellcode jederzeit nahtlos + übernommen und weitergeführt werden. + + + + +); + +export const CrossSellModule = ({ state }: any) => { + const isWebsite = state.projectType === "website"; + const title = isWebsite ? "Weitere Potenziale" : "Websites & Ökosysteme"; + const subtitle = isWebsite + ? "Automatisierung und Prozessoptimierung" + : "Technische Infrastruktur ohne Kompromisse"; + + return ( + <> + + + + {isWebsite ? ( + <> + + + Über die klassische Webpräsenz hinaus werden maßgeschneiderte + Lösungen zur Automatisierung von Routine-Prozessen angeboten. + Dies ermöglicht eine signifikante Effizienzsteigerung im + Tagesgeschäft. + + + Keine Abos. Keine komplexen neuen Systeme. Gezielte + Zeitersparnis. + + + + Individuelle Analyse + + + Spezifische Prozesse werden auf technisches + Automatisierungspotenzial untersucht. Das Ergebnis liefert + Klarheit über die wirtschaftliche Sinnhaftigkeit einer + Umsetzung. + + + + + + + Erstellung von PDF-Angeboten, Berichten oder Protokollen in + Sekunden statt Stunden. + + + + + Intelligente Tabellen und automatisierte Auswertungen + bestehender Datensätze. + + + + + Effiziente Verarbeitung von analogen Dokumenten oder + handschriftlichen Notizen mittels KI. + + + + + ) : ( + + + Bereitstellung einer stabilen technischen Basis ohne + Abhängigkeiten von Baukasten-Systemen oder Agenturen. + + + Entwicklung performanter Frontends und skalierbarer Backends. Die + Auslieferung erfolgt als kontrollierbarer und nachhaltiger + Quellcode. + + + )} + + + ); +}; diff --git a/packages/acquisition-library/src/index.ts b/packages/acquisition-library/src/index.ts index 7e1e588..a0855d4 100644 --- a/packages/acquisition-library/src/index.ts +++ b/packages/acquisition-library/src/index.ts @@ -4,3 +4,13 @@ export * from "./logic/pricing/calculator.js"; export * from "./services/AcquisitionService.js"; export * from "./services/PdfEngine.js"; export * from "./components/EstimationPDF.js"; +export * from "./components/pdf/DINLayout.js"; +export * from "./components/pdf/SimpleLayout.js"; +export * from "./components/pdf/SharedUI.js"; +export * from "./components/pdf/modules/FrontPageModule.js"; +export * from "./components/pdf/modules/BriefingModule.js"; +export * from "./components/pdf/modules/SitemapModule.js"; +export * from "./components/pdf/modules/EstimationModule.js"; +export * from "./components/pdf/modules/CommonModules.js"; +export * from "./components/pdf/modules/BrandingModules.js"; +export * from "./components/pdf/modules/TransparenzModule.js"; diff --git a/packages/acquisition/build.mjs b/packages/acquisition/build.mjs index 382e4e7..69ccd98 100644 --- a/packages/acquisition/build.mjs +++ b/packages/acquisition/build.mjs @@ -21,9 +21,13 @@ build({ platform: 'node', target: 'node18', outfile: outfile, - format: 'esm', - // Bundle everything, including Directus SDK, to avoid resolution issues in Docker - external: ["jsdom", "jsdom/*", "jquery", "jquery/*", "canvas", "fs", "path", "os", "http", "https", "zlib", "stream", "util", "url", "net", "tls", "crypto"], + jsx: 'automatic', + loader: { + '.tsx': 'tsx', + '.ts': 'ts', + '.js': 'js', + }, + external: ["@react-pdf/renderer", "react", "react-dom", "jsdom", "jsdom/*", "jquery", "jquery/*", "canvas", "fs", "path", "os", "http", "https", "zlib", "stream", "util", "url", "net", "tls", "crypto"], plugins: [{ name: 'mock-canvas', setup(build) {