const DS = window.AarnikshaDesignSystem_f93754;
const AKH = window.AKStore.h;
const AppCtx = React.createContext(null);
const useApp = () => React.useContext(AppCtx);
function useStore() {
const [, force] = React.useReducer((x) => x + 1, 0);
React.useEffect(() => window.AKStore.subscribe(force), []);
return window.AKStore.get();
}
/* Lucide outline icons (CDN) drawn at the brand's 1.6 stroke — see HANDOFF.md, "Icon substitution". */
function PIcon({ name, size = 18, stroke = 1.6, color, style }) {
const ref = React.useRef(null);
React.useEffect(() => {
const L = window.lucide; const el = ref.current;
if (!L || !el || !L.icons || !L.icons[name]) return;
const NS = 'http://www.w3.org/2000/svg'; const node = L.icons[name];
const svg = document.createElementNS(NS, 'svg');
const a = { width: size, height: size, viewBox: '0 0 24 24', fill: 'none', stroke: 'currentColor', 'stroke-width': stroke, 'stroke-linecap': 'round', 'stroke-linejoin': 'round' };
Object.keys(a).forEach((k) => svg.setAttribute(k, a[k]));
(Array.isArray(node[0]) ? node : node[2] || []).forEach(([tag, at]) => { const c = document.createElementNS(NS, tag); Object.keys(at).forEach((k) => c.setAttribute(k, at[k])); svg.appendChild(c); });
el.replaceChildren(svg);
}, [name, size, stroke]);
return ;
}
const TONES = { blue: ['#E7F1FD', '#1D6AE3'], green: ['#E3F5EC', '#0F7A55'], amber: ['#FDF1DC', '#8A5A00'], red: ['#FCEAE8', '#B9382F'], grey: ['#EDF1F8', '#4A5670'], navy: ['#06367E', '#FFFFFF'] };
const STATUS = { pending: ['amber', 'Pending'], approved: ['green', 'Approved'], rejected: ['red', 'Declined'], cancelled: ['grey', 'Cancelled'], active: ['green', 'Active'], suspended: ['red', 'Suspended'], todo: ['grey', 'To do'], in_progress: ['blue', 'In progress'], done: ['green', 'Done'] };
function Badge({ tone = 'grey', children, style }) {
const [bg, fg] = TONES[tone];
return {children};
}
const StatusBadge = ({ status }) => {(STATUS[status] || [0, status])[1]};
function Btn({ variant = 'primary', size = 'md', icon, children, full, style, disabled, ...rest }) {
const [h, setH] = React.useState(false);
const on = h && !disabled;
const skins = {
primary: { background: on ? '#06367E' : '#2F80EC', color: '#fff', border: '1px solid transparent', boxShadow: on ? '0 10px 22px rgba(47,128,236,.28)' : 'none' },
outline: { background: '#fff', color: on ? '#06367E' : '#101B33', border: '1px solid ' + (on ? '#06367E' : '#DCE3EE') },
ghost: { background: on ? '#EDF1F8' : 'transparent', color: '#43506A', border: '1px solid transparent' },
danger: { background: on ? '#FCEAE8' : '#fff', color: '#B9382F', border: '1px solid #F2C9C5' },
white: { background: '#fff', color: '#06367E', border: '1px solid transparent', boxShadow: on ? '0 12px 26px rgba(2,22,56,.26)' : '0 8px 20px rgba(2,22,56,.16)' },
glass: { background: on ? 'rgba(255,255,255,.2)' : 'rgba(255,255,255,.1)', color: '#fff', border: '1px solid rgba(255,255,255,.24)' },
};
return (
);
}
function Card({ children, pad = '24px', style, tint }) {
return
{children}
;
}
function CardHead({ title, sub, action, style }) {
return (
{title}
{sub ?
{sub}
: null}
{action || null}
);
}
function PageHeader({ eyebrow, title, sub, actions }) {
const { m } = useApp();
return (
{eyebrow ?
{eyebrow}
: null}
{title}
{sub ?
{sub}
: null}
{actions ?
{actions}
: null}
);
}
function Stat({ label, value, sub, tone }) {
return (
{label}
{value}
{sub ?
{sub}
: null}
);
}
const AV_COLORS = ['#06367E', '#2F80EC', '#0A4497', '#1D6AE3', '#0B4A78', '#123A86'];
function Avatar({ name = '?', size = 36 }) {
const ini = name.split(' ').map((p) => p[0]).slice(0, 2).join('').toUpperCase();
const c = AV_COLORS[[...name].reduce((a, ch) => a + ch.charCodeAt(0), 0) % AV_COLORS.length];
return {ini};
}
function Person({ u, sub, size = 36 }) {
if (!u) return —;
return (
{u.name}
{sub != null ? sub : u.designation}
);
}
function Progress({ value, h = 8, color = '#2F80EC' }) {
return ;
}
function Segmented({ options, value, onChange, dark, full }) {
return (
{options.map(([k, label, count]) => {
const on = value === k;
return (
);
})}
);
}
function Empty({ icon = 'Inbox', title, body }) {
return (
{title}
{body ?
{body}
: null}
);
}
function Modal({ open, onClose, eyebrow, title, children, width = 520 }) {
if (!open) return null;
return {children}
;
}
const inputStyle = { width: '100%', fontSize: '15px', color: '#101B33', background: '#F8FAFE', border: '1px solid #E1E8F4', borderRadius: '12px', padding: '13px 14px', outline: 'none', fontFamily: 'inherit', boxSizing: 'border-box' };
function Label({ children, hint }) {
return {children}{hint ? {hint} : null};
}
function Input({ label, hint, prefix, style, ...rest }) {
const [f, setF] = React.useState(false);
return (
);
}
function Select({ label, options, style, ...rest }) {
return (
{label ? {label} : null}
);
}
function TextArea({ label, hint, rows = 3, style, ...rest }) {
return (
{label ? {label} : null}
);
}
const ErrorLine = ({ children }) => children ? {children}
: null;
const TH = { textAlign: 'left', padding: '12px 16px', fontSize: '11px', fontWeight: 800, letterSpacing: '.1em', textTransform: 'uppercase', color: '#8A94A6', borderBottom: '1px solid #E9EDF5', whiteSpace: 'nowrap', background: '#F8FAFE' };
const TD = { padding: '14px 16px', fontSize: '14px', color: '#43506A', borderBottom: '1px solid #EDF1F8', verticalAlign: 'middle' };
function Table({ head, children, minWidth = 640 }) {
return (
{head.map((h, i) => | ') ? 'right' : 'left' }}>{h && h.replace ? h.replace(/^>/, '') : h} | )}
{children}
);
}
const fmt = {
d: (s) => AKH.parse(s).toLocaleDateString('en-IN', { day: 'numeric', month: 'short' }),
dw: (s) => AKH.parse(s).toLocaleDateString('en-IN', { weekday: 'short', day: 'numeric', month: 'short' }),
long: (s) => AKH.parse(s).toLocaleDateString('en-IN', { weekday: 'long', day: 'numeric', month: 'long', year: 'numeric' }),
range: (a, b) => a === b ? fmt.dw(a) : fmt.d(a) + ' – ' + fmt.d(b),
t: (hm) => { if (!hm) return '—'; const [h, mm] = hm.split(':').map(Number); return ((h + 11) % 12 + 1) + ':' + String(mm).padStart(2, '0') + (h < 12 ? ' am' : ' pm'); },
ago: (isoTs) => { const s = (Date.now() - new Date(isoTs).getTime()) / 1000; if (s < 60) return 'Just now'; if (s < 3600) return Math.floor(s / 60) + 'm ago'; if (s < 86400) return Math.floor(s / 3600) + 'h ago'; const d = Math.floor(s / 86400); return d === 1 ? 'Yesterday' : d + 'd ago'; },
dur: (a, b) => { const m = AKH.mins(b) - AKH.mins(a); return Math.floor(m / 60) + 'h ' + String(m % 60).padStart(2, '0') + 'm'; },
};
const greet = () => { const h = new Date().getHours(); return h < 12 ? 'Good morning' : h < 17 ? 'Good afternoon' : 'Good evening'; };
const firstName = (u) => u.name.split(' ')[0];
function dayInfo(S, userId, k) {
const d = AKH.parse(k); const t = AKH.todayIso();
const u = AKH.user(userId); const rec = (S.attendance[userId] || {})[k];
const hol = AKH.holidayOn(k);
if (rec && rec.status === 'leave') return { kind: 'leave', label: 'Leave', tone: 'amber', rec };
if (AKH.isWeekend(d)) return { kind: 'weekend', label: 'Weekend', tone: null };
if (hol) return { kind: 'holiday', label: hol.name, tone: 'navy', hol };
if (rec && rec.in) {
if (!rec.out && k < t) return { kind: 'missed', label: 'Missed punch', tone: 'red', rec };
return { kind: rec.status, label: rec.status === 'wfh' ? 'WFH' : 'Office', tone: rec.status === 'wfh' ? 'grey' : 'blue', rec, late: AKH.mins(rec.in) > AKH.mins(window.AKStore.LATE_AFTER) };
}
if (k === t) return { kind: 'today', label: 'Not checked in', tone: null };
if (k > t || (u && u.joined && k < u.joined)) return { kind: 'future', label: '', tone: null };
return { kind: 'absent', label: 'Absent', tone: 'red' };
}
Object.assign(window, { DS, AKH, AppCtx, useApp, useStore, PIcon, Badge, StatusBadge, STATUS, Btn, Card, CardHead, PageHeader, Stat, Avatar, Person, Progress, Segmented, Empty, Modal, Input, Select, TextArea, Label, ErrorLine, Table, TH, TD, fmt, greet, firstName, dayInfo, inputStyle });