feat(api, agents, i18n): enhance settlement features and multi-language support
Added new types and API functions for settlement period summaries and credit ledgers, improving the management of agent settlements. Updated the admin console to reflect these changes, enhancing user experience with better navigation and data presentation. Additionally, expanded multi-language support by incorporating new translations in English, Nepali, and Chinese for settlement-related terms, ensuring consistency across the platform.
This commit is contained in:
128
src/components/admin/admin-subnav.tsx
Normal file
128
src/components/admin/admin-subnav.tsx
Normal file
@@ -0,0 +1,128 @@
|
||||
"use client";
|
||||
|
||||
import Link from "next/link";
|
||||
import type { ReactNode } from "react";
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
export function adminSubnavItemClassName(active: boolean, disabled = false): string {
|
||||
if (disabled) {
|
||||
return "border-b-2 border-transparent px-4 py-3 text-sm font-medium text-muted-foreground/45 cursor-not-allowed";
|
||||
}
|
||||
|
||||
return cn(
|
||||
"relative -mb-px shrink-0 border-b-2 px-4 py-3 text-sm font-medium transition-colors",
|
||||
active
|
||||
? "border-primary text-primary"
|
||||
: "border-transparent text-muted-foreground hover:border-border/80 hover:text-foreground",
|
||||
);
|
||||
}
|
||||
|
||||
type AdminSubnavProps = {
|
||||
children: ReactNode;
|
||||
className?: string;
|
||||
/** Accessible name for the tab list */
|
||||
"aria-label": string;
|
||||
};
|
||||
|
||||
/** Underline-style horizontal tab bar used across admin page headers. */
|
||||
export function AdminSubnav({ children, className, "aria-label": ariaLabel }: AdminSubnavProps) {
|
||||
return (
|
||||
<nav
|
||||
aria-label={ariaLabel}
|
||||
className={cn(
|
||||
"flex w-full flex-wrap items-end gap-1 border-b border-border/60 px-1",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</nav>
|
||||
);
|
||||
}
|
||||
|
||||
type AdminSubnavLinkProps = {
|
||||
href: string;
|
||||
active: boolean;
|
||||
children: ReactNode;
|
||||
className?: string;
|
||||
disabled?: boolean;
|
||||
disabledTitle?: string;
|
||||
};
|
||||
|
||||
export function AdminSubnavLink({
|
||||
href,
|
||||
active,
|
||||
children,
|
||||
className,
|
||||
disabled = false,
|
||||
disabledTitle,
|
||||
}: AdminSubnavLinkProps) {
|
||||
if (disabled) {
|
||||
return (
|
||||
<span className={cn(adminSubnavItemClassName(false, true), className)} title={disabledTitle}>
|
||||
{children}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Link href={href} className={cn(adminSubnavItemClassName(active), className)}>
|
||||
{children}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
type AdminSubnavButtonProps = {
|
||||
active: boolean;
|
||||
onClick: () => void;
|
||||
children: ReactNode;
|
||||
className?: string;
|
||||
count?: number;
|
||||
disabled?: boolean;
|
||||
};
|
||||
|
||||
export function AdminSubnavButton({
|
||||
active,
|
||||
onClick,
|
||||
children,
|
||||
className,
|
||||
count,
|
||||
disabled = false,
|
||||
}: AdminSubnavButtonProps) {
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
disabled={disabled}
|
||||
onClick={onClick}
|
||||
className={cn(adminSubnavItemClassName(active, disabled), className)}
|
||||
>
|
||||
{children}
|
||||
{count !== undefined && count > 0 ? (
|
||||
<span
|
||||
className={cn(
|
||||
"ml-1.5 inline-flex min-w-[1.25rem] items-center justify-center rounded-full px-1.5 py-0.5 text-[10px] font-medium tabular-nums",
|
||||
active ? "bg-primary/10 text-primary" : "bg-muted text-muted-foreground",
|
||||
)}
|
||||
>
|
||||
{count}
|
||||
</span>
|
||||
) : null}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
type AdminSubnavBarProps = {
|
||||
children: ReactNode;
|
||||
trailing?: ReactNode;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
/** Wrapper for subnav plus optional trailing controls (site selector, back link, etc.). */
|
||||
export function AdminSubnavBar({ children, trailing, className }: AdminSubnavBarProps) {
|
||||
return (
|
||||
<div className={cn("flex w-full flex-wrap items-end justify-between gap-3", className)}>
|
||||
{children}
|
||||
{trailing ? <div className="shrink-0 pb-1">{trailing}</div> : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user