mirror of
https://dev.azure.com/globalhealthx/EMR/_git/helix-engage
synced 2026-05-18 20:08:19 +00:00
updated login ui and call screen -> tasks ui
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
This commit is contained in:
@@ -145,7 +145,7 @@ export const NavAccountCard = ({
|
||||
}
|
||||
|
||||
return (
|
||||
<div ref={triggerRef} className="relative flex items-center gap-3 rounded-xl p-3">
|
||||
<div ref={triggerRef} className="relative flex items-center gap-3 rounded-xl p-3 border border-secondary">
|
||||
<AvatarLabelGroup
|
||||
size="md"
|
||||
src={selectedAccount.avatar}
|
||||
|
||||
@@ -7,7 +7,7 @@ import { cx, sortCx } from "@/utils/cx";
|
||||
|
||||
const styles = sortCx({
|
||||
root: "group relative flex w-full cursor-pointer items-center rounded-md outline-focus-ring transition duration-100 ease-linear select-none focus-visible:z-10 focus-visible:outline-2 focus-visible:outline-offset-2",
|
||||
rootSelected: "bg-sidebar-active hover:bg-sidebar-active border-l-2 border-l-brand-600",
|
||||
rootSelected: "bg-tertiary hover:bg-tertiary",
|
||||
});
|
||||
|
||||
interface NavItemBaseProps {
|
||||
@@ -34,7 +34,7 @@ interface NavItemBaseProps {
|
||||
}
|
||||
|
||||
export const NavItemBase = ({ current, type, badge, href, icon: Icon, children, truncate = true, onClick }: NavItemBaseProps) => {
|
||||
const iconElement = Icon && <Icon aria-hidden="true" className="mr-2 size-5 shrink-0 text-fg-quaternary transition-inherit-all" />;
|
||||
const iconElement = Icon && <Icon aria-hidden="true" className={cx("mr-2 size-5 shrink-0 transition-inherit-all", current ? "text-brand-secondary" : "text-secondary")} />;
|
||||
|
||||
const badgeElement =
|
||||
badge && (typeof badge === "string" || typeof badge === "number") ? (
|
||||
@@ -48,9 +48,9 @@ export const NavItemBase = ({ current, type, badge, href, icon: Icon, children,
|
||||
const labelElement = (
|
||||
<span
|
||||
className={cx(
|
||||
"flex-1 text-md font-semibold text-white transition-inherit-all",
|
||||
"flex-1 text-md font-semibold transition-inherit-all",
|
||||
truncate && "truncate",
|
||||
current ? "text-sidebar-active" : "group-hover:text-sidebar-hover",
|
||||
current ? "text-brand-secondary" : "text-secondary group-hover:text-primary",
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
@@ -63,7 +63,7 @@ export const NavItemBase = ({ current, type, badge, href, icon: Icon, children,
|
||||
if (type === "collapsible") {
|
||||
return (
|
||||
<summary
|
||||
className={cx("px-3 py-2 bg-sidebar", !current && "hover:bg-sidebar-hover", styles.root, current && styles.rootSelected)}
|
||||
className={cx("px-3 py-2", !current && "hover:bg-primary_hover", styles.root, current && styles.rootSelected)}
|
||||
onClick={onClick}>
|
||||
{iconElement}
|
||||
|
||||
@@ -82,7 +82,7 @@ export const NavItemBase = ({ current, type, badge, href, icon: Icon, children,
|
||||
href={href!}
|
||||
target={isExternal ? "_blank" : "_self"}
|
||||
rel="noopener noreferrer"
|
||||
className={cx("py-2 pr-3 pl-10 bg-sidebar", !current && "hover:bg-sidebar-hover", styles.root, current && styles.rootSelected)}
|
||||
className={cx("py-2 pr-3 pl-10", !current && "hover:bg-primary_hover", styles.root, current && styles.rootSelected)}
|
||||
onClick={onClick}
|
||||
aria-current={current ? "page" : undefined}
|
||||
>
|
||||
@@ -98,7 +98,7 @@ export const NavItemBase = ({ current, type, badge, href, icon: Icon, children,
|
||||
href={href!}
|
||||
target={isExternal ? "_blank" : "_self"}
|
||||
rel="noopener noreferrer"
|
||||
className={cx("px-3 py-2 bg-sidebar", !current && "hover:bg-sidebar-hover", styles.root, current && styles.rootSelected)}
|
||||
className={cx("px-3 py-2", !current && "hover:bg-primary_hover", styles.root, current && styles.rootSelected)}
|
||||
onClick={onClick}
|
||||
aria-current={current ? "page" : undefined}
|
||||
>
|
||||
|
||||
@@ -20,8 +20,8 @@ export const AvatarLabelGroup = ({ title, subtitle, className, ...props }: Avata
|
||||
<figure className={cx("group flex min-w-0 flex-1 items-center", styles[props.size].root, className)}>
|
||||
<Avatar {...props} />
|
||||
<figcaption className="min-w-0 flex-1">
|
||||
<p className={cx("text-white", styles[props.size].title)}>{title}</p>
|
||||
<p className={cx("truncate text-white opacity-70", styles[props.size].subtitle)}>{subtitle}</p>
|
||||
<p className={cx("text-[#374151]", styles[props.size].title)}>{title}</p>
|
||||
<p className={cx("truncate text-[#6b7280]", styles[props.size].subtitle)}>{subtitle}</p>
|
||||
</figcaption>
|
||||
</figure>
|
||||
);
|
||||
|
||||
@@ -63,7 +63,7 @@ export const FileTrigger = (props: FileTriggerProps) => {
|
||||
onChange={(e) => onSelect?.(e.target.files)}
|
||||
capture={defaultCamera}
|
||||
multiple={allowsMultiple}
|
||||
// @ts-expect-error
|
||||
// @ts-expect-error webkitdirectory is a non-standard attribute
|
||||
webkitdirectory={acceptDirectory ? "" : undefined}
|
||||
/>
|
||||
</>
|
||||
|
||||
@@ -82,9 +82,9 @@ export const InputBase = ({
|
||||
ref={groupRef}
|
||||
className={({ isFocusWithin, isDisabled, isInvalid }) =>
|
||||
cx(
|
||||
"relative flex w-full flex-row place-content-center place-items-center rounded-lg bg-primary shadow-xs ring-1 ring-primary transition-shadow duration-100 ease-linear ring-inset",
|
||||
"relative flex w-full flex-row place-content-center place-items-center rounded-lg bg-primary shadow-xs border border-secondary transition-shadow duration-100 ease-linear",
|
||||
|
||||
isFocusWithin && !isDisabled && "ring-2 ring-brand",
|
||||
isFocusWithin && !isDisabled && "ring-2 ring-brand border-transparent",
|
||||
|
||||
// Disabled state styles
|
||||
isDisabled && "cursor-not-allowed bg-disabled_subtle ring-disabled",
|
||||
@@ -122,7 +122,7 @@ export const InputBase = ({
|
||||
ref={ref}
|
||||
placeholder={placeholder}
|
||||
className={cx(
|
||||
"m-0 w-full bg-transparent text-md text-primary ring-0 outline-hidden placeholder:text-placeholder autofill:rounded-lg autofill:text-primary",
|
||||
"m-0 w-full bg-transparent text-md text-primary ring-0 outline-hidden placeholder:text-placeholder autofill:rounded-lg autofill:text-primary autofill:bg-primary autofill:shadow-[inset_0_0_0_1000px_rgb(255_255_255)]",
|
||||
isDisabled && "cursor-not-allowed text-disabled",
|
||||
sizes[inputSize].root,
|
||||
context?.inputClassName,
|
||||
|
||||
@@ -57,8 +57,8 @@ const SelectValue = ({ isOpen, isFocused, isDisabled, size, placeholder, placeho
|
||||
<AriaButton
|
||||
ref={ref}
|
||||
className={cx(
|
||||
"relative flex w-full cursor-pointer items-center rounded-lg bg-primary shadow-xs ring-1 ring-primary outline-hidden transition duration-100 ease-linear ring-inset",
|
||||
(isFocused || isOpen) && "ring-2 ring-brand",
|
||||
"relative flex w-full cursor-pointer items-center rounded-lg bg-primary shadow-xs border border-secondary outline-hidden transition duration-100 ease-linear",
|
||||
(isFocused || isOpen) && "ring-2 ring-brand border-transparent",
|
||||
isDisabled && "cursor-not-allowed bg-disabled_subtle text-disabled",
|
||||
)}
|
||||
>
|
||||
|
||||
@@ -120,7 +120,7 @@ export const AppShell = ({ children }: AppShellProps) => {
|
||||
<div className="flex flex-1 flex-col overflow-hidden">
|
||||
{/* Agent top bar — network indicator + status toggle (agents only) */}
|
||||
{hasAgentConfig && (
|
||||
<div className="flex shrink-0 items-center gap-2 border-b border-secondary px-4 py-2">
|
||||
<div className="flex shrink-0 items-center gap-2 px-4 py-2">
|
||||
<div className="ml-auto flex items-center gap-2">
|
||||
<div className={cx(
|
||||
'flex items-center gap-1.5 rounded-full px-2.5 py-1 text-xs font-medium',
|
||||
|
||||
@@ -20,6 +20,7 @@ import {
|
||||
faPhoneMissed,
|
||||
} from "@fortawesome/pro-duotone-svg-icons";
|
||||
import { faIcon } from "@/lib/icon-wrapper";
|
||||
import { BarChartSquare02 } from "@untitledui/icons";
|
||||
import { useAtom } from "jotai";
|
||||
import { Link, useNavigate } from "react-router";
|
||||
import { ModalOverlay, Modal, Dialog } from "@/components/application/modals/modal";
|
||||
@@ -53,6 +54,7 @@ const IconCalendarCheck = faIcon(faCalendarCheck);
|
||||
const IconTowerBroadcast = faIcon(faTowerBroadcast);
|
||||
const IconFileAudio = faIcon(faFileAudio);
|
||||
const IconPhoneMissed = faIcon(faPhoneMissed);
|
||||
const IconTasks = BarChartSquare02;
|
||||
|
||||
type NavSection = {
|
||||
label: string;
|
||||
@@ -95,6 +97,7 @@ const getNavSections = (role: string): NavSection[] => {
|
||||
return [
|
||||
{ label: 'Call Center', items: [
|
||||
{ label: 'Call Desk', href: '/', icon: IconPhone },
|
||||
{ label: 'Tasks', href: '/tasks', icon: IconTasks },
|
||||
{ label: 'Call History', href: '/call-history', icon: IconClockRewind },
|
||||
{ label: 'Leads', href: '/leads', icon: IconUsers },
|
||||
{ label: 'Contacts', href: '/contacts', icon: IconAddressBook },
|
||||
@@ -121,14 +124,6 @@ const getNavSections = (role: string): NavSection[] => {
|
||||
];
|
||||
};
|
||||
|
||||
const getRoleSubtitle = (role: string): string => {
|
||||
switch (role) {
|
||||
case 'admin': return 'Marketing Admin';
|
||||
case 'cc-agent': return 'Call Center Agent';
|
||||
default: return 'Marketing Executive';
|
||||
}
|
||||
};
|
||||
|
||||
interface SidebarProps {
|
||||
activeUrl?: string;
|
||||
}
|
||||
@@ -172,22 +167,19 @@ export const Sidebar = ({ activeUrl = "/" }: SidebarProps) => {
|
||||
<aside
|
||||
style={{ "--width": `${width}px` } as React.CSSProperties}
|
||||
className={cx(
|
||||
"flex h-full w-full max-w-full flex-col justify-between overflow-auto bg-sidebar pt-4 shadow-xs transition-all duration-200 ease-linear lg:w-(--width) lg:pt-5",
|
||||
"flex h-full w-full max-w-full flex-col justify-between overflow-auto bg-secondary pt-4 shadow-xs transition-all duration-200 ease-linear lg:w-(--width) lg:pt-5",
|
||||
)}
|
||||
>
|
||||
{/* Logo + collapse toggle */}
|
||||
<div className={cx("flex items-center gap-2", collapsed ? "justify-center px-2" : "justify-between px-4 lg:px-5")}>
|
||||
{collapsed ? (
|
||||
<img src={tokens.brand.logo} alt={tokens.brand.name} className="size-8 rounded-lg shrink-0" />
|
||||
<span className="text-lg font-bold text-brand-secondary">H</span>
|
||||
) : (
|
||||
<div className="flex flex-col gap-1">
|
||||
<span className="text-md font-bold text-white">{tokens.sidebar.title}</span>
|
||||
<span className="text-xs text-white opacity-70">{tokens.sidebar.subtitle.replace('{role}', getRoleSubtitle(user.role))}</span>
|
||||
</div>
|
||||
<span className="text-lg font-semibold text-brand-secondary">{tokens.sidebar.title}</span>
|
||||
)}
|
||||
<button
|
||||
onClick={() => setCollapsed(!collapsed)}
|
||||
className="hidden lg:flex size-6 items-center justify-center rounded-md text-fg-quaternary hover:text-fg-secondary hover:bg-secondary transition duration-100 ease-linear"
|
||||
className="hidden lg:flex size-6 items-center justify-center rounded-md text-secondary hover:text-primary hover:bg-primary_hover transition duration-100 ease-linear"
|
||||
title={collapsed ? 'Expand sidebar' : 'Collapse sidebar'}
|
||||
>
|
||||
<FontAwesomeIcon icon={collapsed ? faChevronRight : faChevronLeft} className="size-3" />
|
||||
@@ -198,31 +190,18 @@ export const Sidebar = ({ activeUrl = "/" }: SidebarProps) => {
|
||||
<ul className="mt-6">
|
||||
{navSections.map((group) => (
|
||||
<li key={group.label}>
|
||||
{!collapsed && (
|
||||
<div className="px-5 pb-1 bg-sidebar">
|
||||
<p className="text-xs font-bold text-quaternary uppercase">{group.label}</p>
|
||||
</div>
|
||||
)}
|
||||
<ul className={cx(collapsed ? "px-2 pb-3" : "px-4 pb-5")}>
|
||||
<ul className={cx(collapsed ? "px-2 pb-3" : "px-3 pb-5")}>
|
||||
{group.items.map((item) => (
|
||||
<li key={item.label} className="py-0.5">
|
||||
{collapsed ? (
|
||||
<Link
|
||||
to={item.href ?? '/'}
|
||||
title={item.label}
|
||||
style={
|
||||
item.href !== activeUrl
|
||||
? {
|
||||
"--hover-bg": "var(--color-sidebar-nav-item-hover-bg)",
|
||||
"--hover-text": "var(--color-sidebar-nav-item-hover-text)",
|
||||
} as React.CSSProperties
|
||||
: undefined
|
||||
}
|
||||
className={cx(
|
||||
"flex size-10 items-center justify-center rounded-lg transition duration-100 ease-linear",
|
||||
item.href === activeUrl
|
||||
? "bg-sidebar-active text-sidebar-active"
|
||||
: "text-fg-quaternary hover:bg-(--hover-bg) hover:text-(--hover-text)",
|
||||
? "bg-tertiary text-brand-secondary"
|
||||
: "text-secondary hover:bg-primary_hover hover:text-primary",
|
||||
)}
|
||||
>
|
||||
{item.icon && <item.icon className="size-5" />}
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
import type { ReactNode } from 'react';
|
||||
|
||||
interface TopBarProps {
|
||||
title: string;
|
||||
subtitle?: string;
|
||||
actions?: ReactNode;
|
||||
}
|
||||
|
||||
export const TopBar = ({ title, subtitle }: TopBarProps) => {
|
||||
export const TopBar = ({ title, subtitle, actions }: TopBarProps) => {
|
||||
return (
|
||||
<header className="flex h-14 items-center border-b border-secondary bg-primary px-6">
|
||||
<header className="flex h-14 items-center justify-between bg-primary px-6">
|
||||
<div className="flex flex-col justify-center">
|
||||
<h1 className="text-lg font-bold text-primary">{title}</h1>
|
||||
{subtitle && <p className="text-xs text-tertiary">{subtitle}</p>}
|
||||
</div>
|
||||
{actions && <div className="flex items-center gap-3">{actions}</div>}
|
||||
</header>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user