Files
boc/backups/2026-07-12-1023/landvex-prod/assets/Index-B5xg3G3P.js
T
Bernt 58ca4e68db feat(boc): Complete Business Operations Center v1.0
- Go backend API with full CRUD for all modules (CRM, Sales, Finance, HR, Legal, Marketing, Support, Purchase, Inventory, Projects, Automation, Analytics)
- Rust analytics service with parallel report generation
- C runtime with POSIX shared memory IPC
- PostgreSQL schema with 30+ tables, full migrations
- Redis cache, sessions, pub/sub
- Kafka event streaming with Zookeeper
- WebSocket hub for real-time updates
- Automation engine with cron jobs, workflows, event triggers
- JWT authentication, multi-tenant from start
- Docker Compose with all services
- Nginx reverse proxy with rate limiting
- Integration tests passing
- Feature gap analysis against Fortnox/Odoo/Visma

Refs: BOC-001
2026-07-12 12:41:35 +00:00

2 lines
12 KiB
JavaScript

import{r as u,u as W,a as R,j as e,T as I,M as N,f as J,C as M,b as K,c as w,P as y,d as Q,R as d,e as X,g as Y,h as Z,i as C,k as ee,l as se,m as ae,L as P,n as te,B as re}from"./index-oAPVDf-r.js";import{R as oe}from"./refresh-cw-DEBvxUr1.js";import{C as k}from"./clock-DRtqJZUo.js";import{C as ne}from"./chevron-right-B9rMgght.js";import{c as S,I as le,R as ie}from"./index-DGH-oZ97.js";import{C as ce}from"./circle-alert-C1Hs9zwh.js";import{V as de}from"./video-D6Sip5Dx.js";const b=u.memo(u.forwardRef(({mission:s,userReach:t=5e3},o)=>{const r=W(),{t:a}=R(),l=s.distance!==void 0&&s.distance<=t,n=l&&s.distance!==void 0&&s.distance<=s.radius_meters,i=c=>{switch(c){case"daily":return a("common.daily");case"weekly":return a("common.weekly");case"biweekly":return a("common.biweekly");case"monthly":return a("common.monthly");default:return c}};return e.jsx("div",{ref:o,onClick:()=>r(`/mission/${s.id}`),className:"glass-card p-5 cursor-pointer hover:border-primary/50 active:scale-[0.98] transition-all duration-200 group touch-target",children:e.jsxs("div",{className:"flex items-start justify-between gap-4",children:[e.jsxs("div",{className:"flex-1 min-w-0 space-y-3",children:[e.jsxs("div",{className:"flex items-center gap-2 flex-wrap",children:[s.organization&&e.jsx("span",{className:"text-xs text-muted-foreground bg-secondary/50 px-2.5 py-1.5 rounded-lg",children:s.organization.name}),s.area_name&&e.jsxs("span",{className:"text-xs text-muted-foreground bg-secondary/50 px-2.5 py-1.5 rounded-lg flex items-center gap-1.5",children:[e.jsx(I,{className:"w-3.5 h-3.5 flex-shrink-0"}),e.jsx("span",{className:"truncate max-w-[140px]",children:s.area_name})]}),n&&e.jsx("span",{className:"text-xs bg-success/20 text-success px-2.5 py-1.5 rounded-lg animate-pulse font-medium",children:a("common.available")})]}),e.jsx("h3",{className:"font-semibold text-base text-foreground group-hover:text-primary transition-colors leading-snug",children:s.title}),s.description&&e.jsx("p",{className:"text-sm text-muted-foreground line-clamp-2 leading-relaxed",children:s.description}),e.jsxs("div",{className:"flex flex-wrap items-center gap-x-5 gap-y-2.5 text-xs text-muted-foreground pt-1",children:[s.distance!==void 0&&e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsx(N,{className:"w-4 h-4 text-primary flex-shrink-0"}),e.jsx("span",{className:`font-medium ${l?"text-primary":"text-destructive"}`,children:J(s.distance)})]}),e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsx(M,{className:"w-4 h-4 flex-shrink-0"}),e.jsxs("span",{children:[s.required_photos," ",a("common.photos")]})]}),e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsx(K,{className:"w-4 h-4 text-warning flex-shrink-0"}),e.jsxs("span",{className:"text-warning font-semibold",children:[new Intl.NumberFormat("sv-SE").format(s.reward_credits)," ",a("common.sek")]})]}),s.frequency&&s.frequency!=="once"&&e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsx(oe,{className:"w-4 h-4 text-primary flex-shrink-0"}),e.jsx("span",{className:"text-primary font-medium",children:i(s.frequency)})]}),s.active_until&&e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsx(k,{className:"w-4 h-4 flex-shrink-0"}),e.jsxs("span",{children:[a("common.until")," ",new Date(s.active_until).toLocaleDateString("sv-SE")]})]}),!s.active_until&&s.expires_at&&e.jsxs("div",{className:"flex items-center gap-1.5",children:[e.jsx(k,{className:"w-4 h-4 flex-shrink-0"}),e.jsx("span",{children:new Date(s.expires_at).toLocaleDateString("sv-SE")})]})]})]}),e.jsx("div",{className:"flex items-center justify-center w-10 h-10 rounded-full bg-secondary/50 group-hover:bg-primary/20 transition-colors flex-shrink-0 self-center",children:e.jsx(ne,{className:"w-5 h-5 text-muted-foreground group-hover:text-primary transition-colors"})})]})})}));b.displayName="MissionCard";var E="Toggle",G=u.forwardRef((s,t)=>{const{pressed:o,defaultPressed:r,onPressedChange:a,...l}=s,[n,i]=w({prop:o,onChange:a,defaultProp:r??!1,caller:E});return e.jsx(y.button,{type:"button","aria-pressed":n,"data-state":n?"on":"off","data-disabled":s.disabled?"":void 0,...l,ref:t,onClick:Q(s.onClick,()=>{s.disabled||i(!n)})})});G.displayName=E;var V=G,g="ToggleGroup",[F]=X(g,[S]),A=S(),T=d.forwardRef((s,t)=>{const{type:o,...r}=s;if(o==="single"){const a=r;return e.jsx(me,{...a,ref:t})}if(o==="multiple"){const a=r;return e.jsx(ue,{...a,ref:t})}throw new Error(`Missing prop \`type\` expected on \`${g}\``)});T.displayName=g;var[D,L]=F(g),me=d.forwardRef((s,t)=>{const{value:o,defaultValue:r,onValueChange:a=()=>{},...l}=s,[n,i]=w({prop:o,defaultProp:r??"",onChange:a,caller:g});return e.jsx(D,{scope:s.__scopeToggleGroup,type:"single",value:d.useMemo(()=>n?[n]:[],[n]),onItemActivate:i,onItemDeactivate:d.useCallback(()=>i(""),[i]),children:e.jsx($,{...l,ref:t})})}),ue=d.forwardRef((s,t)=>{const{value:o,defaultValue:r,onValueChange:a=()=>{},...l}=s,[n,i]=w({prop:o,defaultProp:r??[],onChange:a,caller:g}),c=d.useCallback(m=>i((x=[])=>[...x,m]),[i]),f=d.useCallback(m=>i((x=[])=>x.filter(h=>h!==m)),[i]);return e.jsx(D,{scope:s.__scopeToggleGroup,type:"multiple",value:n,onItemActivate:c,onItemDeactivate:f,children:e.jsx($,{...l,ref:t})})});T.displayName=g;var[xe,pe]=F(g),$=d.forwardRef((s,t)=>{const{__scopeToggleGroup:o,disabled:r=!1,rovingFocus:a=!0,orientation:l,dir:n,loop:i=!0,...c}=s,f=A(o),m=Y(n),x={role:"group",dir:m,...c};return e.jsx(xe,{scope:o,rovingFocus:a,disabled:r,children:a?e.jsx(ie,{asChild:!0,...f,orientation:l,dir:m,loop:i,children:e.jsx(y.div,{...x,ref:t})}):e.jsx(y.div,{...x,ref:t})})}),j="ToggleGroupItem",z=d.forwardRef((s,t)=>{const o=L(j,s.__scopeToggleGroup),r=pe(j,s.__scopeToggleGroup),a=A(s.__scopeToggleGroup),l=o.value.includes(s.value),n=r.disabled||s.disabled,i={...s,pressed:l,disabled:n},c=d.useRef(null);return r.rovingFocus?e.jsx(le,{asChild:!0,...a,focusable:!n,active:l,ref:c,children:e.jsx(_,{...i,ref:t})}):e.jsx(_,{...i,ref:t})});z.displayName=j;var _=d.forwardRef((s,t)=>{const{__scopeToggleGroup:o,value:r,...a}=s,l=L(j,o),n={role:"radio","aria-checked":s.pressed,"aria-pressed":void 0},i=l.type==="single"?n:void 0;return e.jsx(G,{...i,...a,ref:t,onPressedChange:c=>{c?l.onItemActivate(r):l.onItemDeactivate(r)}})}),q=T,B=z;const O=Z("inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors hover:bg-muted hover:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground",{variants:{variant:{default:"bg-transparent",outline:"border border-input bg-transparent hover:bg-accent hover:text-accent-foreground"},size:{default:"h-10 px-3",sm:"h-9 px-2.5",lg:"h-11 px-5"}},defaultVariants:{variant:"default",size:"default"}}),ge=u.forwardRef(({className:s,variant:t,size:o,...r},a)=>e.jsx(V,{ref:a,className:C(O({variant:t,size:o,className:s})),...r}));ge.displayName=V.displayName;const H=u.createContext({size:"default",variant:"default"}),U=u.forwardRef(({className:s,variant:t,size:o,children:r,...a},l)=>e.jsx(q,{ref:l,className:C("flex items-center justify-center gap-1",s),...a,children:e.jsx(H.Provider,{value:{variant:t,size:o},children:r})}));U.displayName=q.displayName;const v=u.forwardRef(({className:s,children:t,variant:o,size:r,...a},l)=>{const n=u.useContext(H);return e.jsx(B,{ref:l,className:C(O({variant:n.variant||o,size:n.size||r}),s),...a,children:t})});v.displayName=B.displayName;const fe=()=>{const{t:s}=R(),[t,o]=u.useState("all"),{latitude:r,longitude:a,loading:l,error:n}=ee(),{activeClaim:i}=se(),{missions:c,loading:f,error:m,isFocusMode:x}=ae(r,a,{activeClaimMissionId:i==null?void 0:i.mission_id}),h=c;return f&&!n?e.jsxs("div",{className:"flex flex-col items-center justify-center py-16 gap-4",children:[e.jsx(P,{className:"w-8 h-8 animate-spin text-primary"}),e.jsx("p",{className:"text-muted-foreground text-sm",children:s(l?"map.gettingLocation":"common.loading")})]}):f?e.jsxs("div",{className:"flex flex-col items-center justify-center py-16 gap-4",children:[e.jsx(P,{className:"w-8 h-8 animate-spin text-primary"}),e.jsx("p",{className:"text-muted-foreground text-sm",children:s("common.loading")})]}):m?e.jsxs("div",{className:"glass-card p-6 text-center space-y-4",children:[e.jsx("div",{className:"w-12 h-12 mx-auto rounded-full bg-destructive/20 flex items-center justify-center",children:e.jsx(ce,{className:"w-6 h-6 text-destructive"})}),e.jsxs("div",{children:[e.jsx("h3",{className:"font-semibold text-foreground",children:s("missions.loadError")}),e.jsx("p",{className:"text-sm text-muted-foreground mt-1",children:m})]})]}):x&&c.length===1?e.jsxs("div",{className:"space-y-5",children:[e.jsxs("div",{className:"flex items-center gap-2.5 text-sm text-primary",children:[e.jsx(I,{className:"w-4 h-4"}),e.jsx("span",{className:"font-medium",children:s("missions.focusMode")})]}),e.jsx("div",{className:"space-y-4",children:c.map(p=>e.jsx(b,{mission:p},p.id))})]}):c.length===0?e.jsxs("div",{className:"glass-card p-6 text-center space-y-4",children:[e.jsx("div",{className:"w-12 h-12 mx-auto rounded-full bg-secondary flex items-center justify-center",children:e.jsx(N,{className:"w-6 h-6 text-muted-foreground"})}),e.jsxs("div",{children:[e.jsx("h3",{className:"font-semibold text-foreground",children:s("home.noMissions")}),e.jsx("p",{className:"text-sm text-muted-foreground mt-1",children:s("missions.noMissionsInArea")})]})]}):e.jsxs("div",{className:"space-y-5",children:[e.jsx("div",{className:"flex items-center gap-2",children:e.jsxs(U,{type:"single",value:t,onValueChange:p=>p&&o(p),className:"bg-muted/50 rounded-lg p-1",children:[e.jsxs(v,{value:"all","aria-label":s("common.all"),className:"text-xs px-3 py-1.5 rounded-md data-[state=on]:bg-primary data-[state=on]:text-primary-foreground data-[state=on]:shadow-sm",children:[s("common.all"),e.jsxs("span",{className:"ml-1 opacity-70",children:["(",c.length,")"]})]}),e.jsxs(v,{value:"photo","aria-label":s("missions.photo"),className:"text-xs px-3 py-1.5 rounded-md gap-1 data-[state=on]:bg-primary data-[state=on]:text-primary-foreground data-[state=on]:shadow-sm",children:[e.jsx(M,{className:"w-3 h-3"}),s("missions.photoShort"),e.jsxs("span",{className:"ml-1 opacity-70",children:["(",c.length,")"]})]}),e.jsxs(v,{value:"video","aria-label":s("missions.video"),className:"text-xs px-3 py-1.5 rounded-md gap-1 data-[state=on]:bg-primary data-[state=on]:text-primary-foreground data-[state=on]:shadow-sm",children:[e.jsx(de,{className:"w-3 h-3"}),s("missions.videoShort"),e.jsx("span",{className:"ml-1 opacity-70",children:"(0)"})]})]})}),n&&e.jsxs("div",{className:"flex items-center gap-2.5 text-sm text-warning bg-warning/10 px-3 py-2 rounded-lg border border-warning/20",children:[e.jsx(N,{className:"w-4 h-4 flex-shrink-0"}),e.jsx("span",{children:"Platsåtkomst saknas — uppdrag visas utan avstånd"})]}),!n&&e.jsxs("div",{className:"flex items-center gap-2.5 text-sm text-muted-foreground",children:[e.jsx("div",{className:"w-2.5 h-2.5 rounded-full bg-success animate-pulse flex-shrink-0"}),e.jsx("span",{children:s("missions.showingMissions",{count:h.length})})]}),e.jsx("div",{className:"space-y-4",children:h.length>0?h.map(p=>e.jsx(b,{mission:p},p.id)):e.jsx("div",{className:"glass-card p-6 text-center",children:e.jsx("p",{className:"text-muted-foreground text-sm",children:s("missions.noMissionsNearby")})})})]})},Ce=()=>{const{canOrder:s}=te();return e.jsxs("div",{className:"min-h-screen-safe bg-background text-foreground pb-32 safe-area-x",children:[e.jsx("main",{className:`px-5 py-5 ${s?"pt-3":"safe-area-top"}`,children:e.jsx(fe,{})}),e.jsx(re,{})]})};export{Ce as default};