- GameRules currencySymbol switches from text to a media upload - new CurrencyAmount/CurrencySymbol components; render sites across banking, base management, dashboard, market, campaigns and profiles are wired to show the emblem inline with amounts - migration 20260921_140000 (text column out, media fk in); registers the five pending migrations in the migrations index
85 lines
3.1 KiB
TypeScript
85 lines
3.1 KiB
TypeScript
"use client";
|
|
|
|
import { BadgeCheckIcon } from "lucide-react";
|
|
import type { CurrencyConfig } from "@/lib/banking/format";
|
|
import { CurrencyAmount } from "@/components/frontend/banking/CurrencyAmount";
|
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
|
import { HireStaffDialog } from "@/components/frontend/baseManagement/HireStaffDialog";
|
|
import type { LaborClassificationOption, StructureStaffingOption } from "@/lib/base";
|
|
|
|
interface EmploymentCardProps {
|
|
readonly employment: {
|
|
readonly positionTitle: string;
|
|
readonly positionType: string;
|
|
readonly structureName: string;
|
|
readonly salary: number;
|
|
} | null;
|
|
readonly structures: readonly StructureStaffingOption[];
|
|
readonly canManage: boolean;
|
|
readonly npcId: number;
|
|
readonly npcName?: string;
|
|
readonly classifications?: readonly LaborClassificationOption[];
|
|
readonly hiringEnabled: boolean;
|
|
readonly hiringDisabledMessage?: string;
|
|
readonly currencyConfig: CurrencyConfig;
|
|
}
|
|
|
|
export function EmploymentCard({
|
|
employment,
|
|
structures,
|
|
canManage,
|
|
npcId,
|
|
npcName,
|
|
classifications,
|
|
hiringEnabled,
|
|
hiringDisabledMessage,
|
|
currencyConfig,
|
|
}: EmploymentCardProps) {
|
|
return (
|
|
<Card>
|
|
<CardHeader className="gap-2">
|
|
<CardTitle className="flex items-center gap-2">
|
|
<BadgeCheckIcon className="size-4 text-muted-foreground" />
|
|
Employment
|
|
</CardTitle>
|
|
<CardDescription>Current base assignment and compensation.</CardDescription>
|
|
</CardHeader>
|
|
<CardContent>
|
|
{employment ? (
|
|
<div className="flex flex-col gap-2">
|
|
<p className="font-medium">{employment.positionTitle}</p>
|
|
<p className="text-sm text-muted-foreground">
|
|
{employment.positionType} · {employment.structureName}
|
|
</p>
|
|
<p className="font-mono text-sm tabular-nums">
|
|
<CurrencyAmount value={employment.salary} currency={currencyConfig} />/tick
|
|
</p>
|
|
</div>
|
|
) : canManage && hiringEnabled ? (
|
|
<div className="flex flex-wrap items-center justify-between gap-3">
|
|
<p className="text-sm text-muted-foreground">Not currently employed.</p>
|
|
<HireStaffDialog
|
|
structures={structures}
|
|
npcs={[{ id: npcId, name: npcName ?? `NPC #${npcId}` }]}
|
|
fixedNpcId={npcId}
|
|
canManage={canManage}
|
|
classifications={classifications}
|
|
hiringEnabled={hiringEnabled}
|
|
hiringDisabledMessage={hiringDisabledMessage}
|
|
currencyConfig={currencyConfig}
|
|
/>
|
|
</div>
|
|
) : canManage ? (
|
|
<div className="flex flex-col gap-2">
|
|
<p className="text-sm text-muted-foreground">Not currently employed.</p>
|
|
<p className="text-sm text-muted-foreground">
|
|
{hiringDisabledMessage || "Staff hiring is currently disabled."}
|
|
</p>
|
|
</div>
|
|
) : (
|
|
<p className="text-sm text-muted-foreground">Not currently employed.</p>
|
|
)}
|
|
</CardContent>
|
|
</Card>
|
|
);
|
|
}
|