feat: status selectors update
This commit is contained in:
@@ -80,6 +80,8 @@ import {
|
|||||||
import { Checkbox } from "@/components/ui/checkbox";
|
import { Checkbox } from "@/components/ui/checkbox";
|
||||||
import { ColumnSelectorDialog } from "@/components/column-selector-dialog";
|
import { ColumnSelectorDialog } from "@/components/column-selector-dialog";
|
||||||
import { CreativeSelectDialog } from "@/components/creative-select-dialog";
|
import { CreativeSelectDialog } from "@/components/creative-select-dialog";
|
||||||
|
import { PlacementStatusSelector } from "@/components/placement-status-selector";
|
||||||
|
import { PlacementPostStatusSelector } from "@/components/placement-post-status-selector";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import type {
|
import type {
|
||||||
Project,
|
Project,
|
||||||
@@ -98,10 +100,12 @@ import {
|
|||||||
PLACEMENT_DEAL_STATUSES,
|
PLACEMENT_DEAL_STATUSES,
|
||||||
PLACEMENT_POST_STATUSES,
|
PLACEMENT_POST_STATUSES,
|
||||||
canEditPostStatus,
|
canEditPostStatus,
|
||||||
|
getPlacementStatusColor,
|
||||||
} from "@/lib/config/placement-columns";
|
} from "@/lib/config/placement-columns";
|
||||||
|
|
||||||
type PlacementInlineDraft = {
|
type PlacementInlineDraft = {
|
||||||
status?: PlacementStatus;
|
status?: PlacementStatus;
|
||||||
|
post_status?: PlacementPostStatus | null;
|
||||||
comment?: string | null;
|
comment?: string | null;
|
||||||
creative_id?: string | null;
|
creative_id?: string | null;
|
||||||
creative_name?: string | null;
|
creative_name?: string | null;
|
||||||
@@ -114,7 +118,7 @@ type PlacementInlineDraft = {
|
|||||||
cpm?: number | null;
|
cpm?: number | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
type EditableField = "status" | "placement_at" | "payment_at" | "cost" | "cost_before_bargain" | "format" | "comment" | "cost_format" | "cpm" | "creative_id" | "creative_name";
|
type EditableField = "status" | "post_status" | "placement_at" | "payment_at" | "cost" | "cost_before_bargain" | "format" | "comment" | "cost_format" | "cpm" | "creative_id" | "creative_name";
|
||||||
|
|
||||||
const FIXED_COST_TYPE: CostType = "fixed";
|
const FIXED_COST_TYPE: CostType = "fixed";
|
||||||
|
|
||||||
@@ -262,25 +266,6 @@ function CellRenderer({
|
|||||||
}: CellRendererProps) {
|
}: CellRendererProps) {
|
||||||
const isEditing = editingCell?.placementId === placement.id;
|
const isEditing = editingCell?.placementId === placement.id;
|
||||||
|
|
||||||
const getStatusColor = (status: PlacementStatus): string => {
|
|
||||||
switch (status) {
|
|
||||||
case "Оплачено":
|
|
||||||
return "bg-emerald-100 text-emerald-700 border-emerald-200 dark:bg-emerald-900/30 dark:text-emerald-400 dark:border-emerald-800";
|
|
||||||
case "Согласование условий":
|
|
||||||
case "Ждём ответа":
|
|
||||||
return "bg-amber-100 text-amber-700 border-amber-200 dark:bg-amber-900/30 dark:text-amber-400 dark:border-amber-800";
|
|
||||||
case "Отмена":
|
|
||||||
case "Не подходит цена":
|
|
||||||
case "Неактуально":
|
|
||||||
case "Не отвечает":
|
|
||||||
return "bg-red-100 text-red-700 border-red-200 dark:bg-red-900/30 dark:text-red-400 dark:border-red-800";
|
|
||||||
case "Оплатить":
|
|
||||||
return "bg-blue-100 text-blue-700 border-blue-200 dark:bg-blue-900/30 dark:text-blue-400 dark:border-blue-800";
|
|
||||||
default:
|
|
||||||
return "bg-muted text-muted-foreground border-border";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const formatCurrency = (value: number): string => {
|
const formatCurrency = (value: number): string => {
|
||||||
return new Intl.NumberFormat("ru-RU", {
|
return new Intl.NumberFormat("ru-RU", {
|
||||||
style: "currency",
|
style: "currency",
|
||||||
@@ -358,43 +343,14 @@ function CellRenderer({
|
|||||||
case "status_deal":
|
case "status_deal":
|
||||||
return (
|
return (
|
||||||
<td key={column.id} className="py-2 px-3">
|
<td key={column.id} className="py-2 px-3">
|
||||||
{isEditing && editingCell?.field === "status" ? (
|
<PlacementStatusSelector
|
||||||
<select
|
status={placement.status}
|
||||||
aria-label="Статус размещения"
|
isEditing={isEditing && editingCell?.field === "status"}
|
||||||
className={cn(
|
canEdit={canEdit}
|
||||||
"h-7 w-full rounded-md border border-input bg-background px-2 text-xs font-medium shadow-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
|
onEdit={() => canEdit && setEditingCell({ placementId: placement.id, field: "status" })}
|
||||||
getStatusColor(placement.status)
|
onChange={(s) => handleDraftChange(placement.id, { status: s })}
|
||||||
)}
|
onCloseEdit={() => setEditingCell(null)}
|
||||||
value={placement.status}
|
/>
|
||||||
onChange={(e) =>
|
|
||||||
handleDraftChange(placement.id, {
|
|
||||||
status: e.target.value as PlacementStatus,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
onBlur={() => setEditingCell(null)}
|
|
||||||
>
|
|
||||||
{PLACEMENT_DEAL_STATUSES.map((status) => (
|
|
||||||
<option key={status} value={status}>
|
|
||||||
{status}
|
|
||||||
</option>
|
|
||||||
))}
|
|
||||||
</select>
|
|
||||||
) : (
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
disabled={!canEdit}
|
|
||||||
className={cn(
|
|
||||||
"group h-7 w-full rounded-md border px-2 text-xs font-medium shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-default flex items-center justify-between gap-2",
|
|
||||||
getStatusColor(placement.status)
|
|
||||||
)}
|
|
||||||
onClick={() =>
|
|
||||||
canEdit && setEditingCell({ placementId: placement.id, field: "status" })
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<span>{placement.status}</span>
|
|
||||||
<Pencil className="h-3 w-3 opacity-0 group-hover:opacity-70 transition-opacity" />
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</td>
|
</td>
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -402,13 +358,14 @@ function CellRenderer({
|
|||||||
const postStatus = placement.placement_post?.status;
|
const postStatus = placement.placement_post?.status;
|
||||||
return (
|
return (
|
||||||
<td key={column.id} className="py-2 px-3">
|
<td key={column.id} className="py-2 px-3">
|
||||||
{postStatus ? (
|
<PlacementPostStatusSelector
|
||||||
<span className="text-xs px-2 py-1 rounded border inline-block">
|
status={postStatus ?? null}
|
||||||
{postStatus}
|
isEditing={isEditing && editingCell?.field === "post_status"}
|
||||||
</span>
|
canEdit={canEdit}
|
||||||
) : (
|
onEdit={() => canEdit && setEditingCell({ placementId: placement.id, field: "post_status" })}
|
||||||
<span className="text-muted-foreground">—</span>
|
onChange={(s) => handleDraftChange(placement.id, { post_status: s })}
|
||||||
)}
|
onCloseEdit={() => setEditingCell(null)}
|
||||||
|
/>
|
||||||
</td>
|
</td>
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -1070,36 +1027,36 @@ function ChannelGroup({
|
|||||||
? (effectiveCost / viewPlacement.placement_post.views_count) * 1000
|
? (effectiveCost / viewPlacement.placement_post.views_count) * 1000
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<tr
|
<tr
|
||||||
key={placement.id}
|
key={placement.id}
|
||||||
data-placement-id={placement.id}
|
data-placement-id={placement.id}
|
||||||
className="border-b last:border-0 hover:bg-muted/30"
|
className="border-b last:border-0 hover:bg-muted/30"
|
||||||
>
|
>
|
||||||
{ALL_COLUMNS.filter((c) => visibleColumns.has(c.id)).map((column) => (
|
{ALL_COLUMNS.filter((c) => visibleColumns.has(c.id)).map((column) => (
|
||||||
<CellRenderer
|
<CellRenderer
|
||||||
key={column.id}
|
key={column.id}
|
||||||
column={column}
|
column={column}
|
||||||
placement={viewPlacement}
|
placement={viewPlacement}
|
||||||
idx={idx}
|
idx={idx}
|
||||||
channelNumber={channelNumber}
|
channelNumber={channelNumber}
|
||||||
canEdit={canEdit}
|
canEdit={canEdit}
|
||||||
editingCell={editingCell}
|
editingCell={editingCell}
|
||||||
setEditingCell={setEditingCell}
|
setEditingCell={setEditingCell}
|
||||||
handleDraftChange={handleDraftChange}
|
handleDraftChange={handleDraftChange}
|
||||||
effectiveCost={effectiveCost}
|
effectiveCost={effectiveCost}
|
||||||
cpf={cpf}
|
cpf={cpf}
|
||||||
cpm={cpm}
|
cpm={cpm}
|
||||||
selectedPlacementIds={selectedPlacementIds}
|
selectedPlacementIds={selectedPlacementIds}
|
||||||
onTogglePlacement={onTogglePlacement}
|
onTogglePlacement={onTogglePlacement}
|
||||||
onOpenCreativeSelect={onOpenCreativeSelect}
|
onOpenCreativeSelect={onOpenCreativeSelect}
|
||||||
onClearCreative={onClearCreative}
|
onClearCreative={onClearCreative}
|
||||||
onOpenCreativeSend={onOpenCreativeSend}
|
onOpenCreativeSend={onOpenCreativeSend}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</tr>
|
</tr>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
@@ -1313,6 +1270,10 @@ export default function PurchasePlanDetailPage() {
|
|||||||
const nextStatus = draft.status ?? placement.status;
|
const nextStatus = draft.status ?? placement.status;
|
||||||
const nextComment = draft.comment !== undefined ? draft.comment : placement.comment;
|
const nextComment = draft.comment !== undefined ? draft.comment : placement.comment;
|
||||||
|
|
||||||
|
const nextPlacementPost = draft.post_status !== null && draft.post_status !== undefined && placement.placement_post
|
||||||
|
? { ...placement.placement_post, status: draft.post_status }
|
||||||
|
: placement.placement_post;
|
||||||
|
|
||||||
const nextDetails = {
|
const nextDetails = {
|
||||||
...(placement.details || {
|
...(placement.details || {
|
||||||
placement_at: null,
|
placement_at: null,
|
||||||
@@ -1357,6 +1318,7 @@ export default function PurchasePlanDetailPage() {
|
|||||||
return {
|
return {
|
||||||
...placement,
|
...placement,
|
||||||
status: nextStatus,
|
status: nextStatus,
|
||||||
|
placement_post: nextPlacementPost,
|
||||||
comment: nextComment,
|
comment: nextComment,
|
||||||
creative_id: draft.creative_id ?? placement.creative_id,
|
creative_id: draft.creative_id ?? placement.creative_id,
|
||||||
creative_name: draft.creative_name ?? placement.creative_name,
|
creative_name: draft.creative_name ?? placement.creative_name,
|
||||||
|
|||||||
110
components/placement-post-status-selector.tsx
Normal file
110
components/placement-post-status-selector.tsx
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { Pencil } from "lucide-react";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
import type { PlacementPostStatus } from "@/lib/types/api";
|
||||||
|
import {
|
||||||
|
PLACEMENT_POST_STATUSES,
|
||||||
|
getPlacementPostStatusIcon,
|
||||||
|
getPlacementPostStatusColor,
|
||||||
|
canEditPostStatus,
|
||||||
|
} from "@/lib/config/placement-columns";
|
||||||
|
import {
|
||||||
|
Popover,
|
||||||
|
PopoverContent,
|
||||||
|
PopoverTrigger,
|
||||||
|
} from "@/components/ui/popover";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
|
||||||
|
interface PlacementPostStatusSelectorProps {
|
||||||
|
status: PlacementPostStatus | null;
|
||||||
|
isEditing: boolean;
|
||||||
|
canEdit: boolean;
|
||||||
|
onEdit: () => void;
|
||||||
|
onChange: (status: PlacementPostStatus) => void;
|
||||||
|
onCloseEdit: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function PlacementPostStatusSelector({
|
||||||
|
status,
|
||||||
|
isEditing,
|
||||||
|
canEdit,
|
||||||
|
onEdit,
|
||||||
|
onChange,
|
||||||
|
onCloseEdit,
|
||||||
|
}: PlacementPostStatusSelectorProps) {
|
||||||
|
if (!status) {
|
||||||
|
return <span className="text-muted-foreground text-xs">—</span>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const canEditThisStatus = canEdit && canEditPostStatus(status);
|
||||||
|
const StatusIcon = getPlacementPostStatusIcon(status);
|
||||||
|
const statusColor = getPlacementPostStatusColor(status);
|
||||||
|
|
||||||
|
if (isEditing && canEditThisStatus) {
|
||||||
|
return (
|
||||||
|
<Popover open={isEditing} onOpenChange={(open) => !open && onCloseEdit()}>
|
||||||
|
<PopoverTrigger asChild>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
className={cn(
|
||||||
|
"h-7 w-full justify-between px-2 text-xs font-medium border shadow-sm",
|
||||||
|
statusColor
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div className="flex items-center gap-1.5">
|
||||||
|
<StatusIcon className="h-3.5 w-3.5" />
|
||||||
|
<span>{status}</span>
|
||||||
|
</div>
|
||||||
|
</Button>
|
||||||
|
</PopoverTrigger>
|
||||||
|
<PopoverContent className="w-72 p-1" align="start">
|
||||||
|
<div className="flex flex-col gap-0.5">
|
||||||
|
{PLACEMENT_POST_STATUSES.map((s) => {
|
||||||
|
const Icon = getPlacementPostStatusIcon(s);
|
||||||
|
const color = getPlacementPostStatusColor(s);
|
||||||
|
const isSelected = s === status;
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
key={s}
|
||||||
|
type="button"
|
||||||
|
className={cn(
|
||||||
|
"flex items-center gap-2 px-2 py-1.5 text-xs rounded-md transition-colors",
|
||||||
|
isSelected
|
||||||
|
? "bg-muted font-medium"
|
||||||
|
: "hover:bg-muted/50"
|
||||||
|
)}
|
||||||
|
onClick={() => {
|
||||||
|
onChange(s);
|
||||||
|
onCloseEdit();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Icon className={cn("h-3.5 w-3.5 shrink-0", color)} />
|
||||||
|
<span className="flex-1 text-left">{s}</span>
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</PopoverContent>
|
||||||
|
</Popover>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
disabled={!canEditThisStatus}
|
||||||
|
className={cn(
|
||||||
|
"group h-7 w-full rounded-md border px-2 text-xs font-medium shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-default flex items-center justify-between gap-2",
|
||||||
|
statusColor
|
||||||
|
)}
|
||||||
|
onClick={onEdit}
|
||||||
|
>
|
||||||
|
<div className="flex items-center gap-1.5">
|
||||||
|
<StatusIcon className="h-3.5 w-3.5" />
|
||||||
|
<span>{status}</span>
|
||||||
|
</div>
|
||||||
|
{canEditThisStatus && <Pencil className="h-3 w-3 opacity-0 group-hover:opacity-70 transition-opacity" />}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
||||||
105
components/placement-status-selector.tsx
Normal file
105
components/placement-status-selector.tsx
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { Pencil, Check } from "lucide-react";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
import type { PlacementStatus } from "@/lib/types/api";
|
||||||
|
import {
|
||||||
|
PLACEMENT_DEAL_STATUSES,
|
||||||
|
getPlacementStatusIcon,
|
||||||
|
getPlacementStatusColor,
|
||||||
|
} from "@/lib/config/placement-columns";
|
||||||
|
import {
|
||||||
|
Popover,
|
||||||
|
PopoverContent,
|
||||||
|
PopoverTrigger,
|
||||||
|
} from "@/components/ui/popover";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
|
||||||
|
interface PlacementStatusSelectorProps {
|
||||||
|
status: PlacementStatus;
|
||||||
|
isEditing: boolean;
|
||||||
|
canEdit: boolean;
|
||||||
|
onEdit: () => void;
|
||||||
|
onChange: (status: PlacementStatus) => void;
|
||||||
|
onCloseEdit: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function PlacementStatusSelector({
|
||||||
|
status,
|
||||||
|
isEditing,
|
||||||
|
canEdit,
|
||||||
|
onEdit,
|
||||||
|
onChange,
|
||||||
|
onCloseEdit,
|
||||||
|
}: PlacementStatusSelectorProps) {
|
||||||
|
const StatusIcon = getPlacementStatusIcon(status);
|
||||||
|
const statusColor = getPlacementStatusColor(status);
|
||||||
|
|
||||||
|
if (isEditing) {
|
||||||
|
return (
|
||||||
|
<Popover open={isEditing} onOpenChange={(open) => !open && onCloseEdit()}>
|
||||||
|
<PopoverTrigger asChild>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
className={cn(
|
||||||
|
"h-7 w-full justify-between px-2 text-xs font-medium border shadow-sm",
|
||||||
|
statusColor
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div className="flex items-center gap-1.5">
|
||||||
|
<StatusIcon className="h-3.5 w-3.5" />
|
||||||
|
<span>{status}</span>
|
||||||
|
</div>
|
||||||
|
</Button>
|
||||||
|
</PopoverTrigger>
|
||||||
|
<PopoverContent className="w-64 p-1" align="start">
|
||||||
|
<div className="flex flex-col gap-0.5">
|
||||||
|
{PLACEMENT_DEAL_STATUSES.map((s) => {
|
||||||
|
const Icon = getPlacementStatusIcon(s);
|
||||||
|
const color = getPlacementStatusColor(s);
|
||||||
|
const isSelected = s === status;
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
key={s}
|
||||||
|
type="button"
|
||||||
|
className={cn(
|
||||||
|
"flex items-center gap-2 px-2 py-1.5 text-xs rounded-md transition-colors",
|
||||||
|
isSelected
|
||||||
|
? "bg-muted font-medium"
|
||||||
|
: "hover:bg-muted/50"
|
||||||
|
)}
|
||||||
|
onClick={() => {
|
||||||
|
onChange(s);
|
||||||
|
onCloseEdit();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Icon className={cn("h-3.5 w-3.5", color)} />
|
||||||
|
<span className="flex-1 text-left">{s}</span>
|
||||||
|
{isSelected && <Check className="h-3 w-3" />}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</PopoverContent>
|
||||||
|
</Popover>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
disabled={!canEdit}
|
||||||
|
className={cn(
|
||||||
|
"group h-7 w-full rounded-md border px-2 text-xs font-medium shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-default flex items-center justify-between gap-2",
|
||||||
|
statusColor
|
||||||
|
)}
|
||||||
|
onClick={onEdit}
|
||||||
|
>
|
||||||
|
<div className="flex items-center gap-1.5">
|
||||||
|
<StatusIcon className="h-3.5 w-3.5" />
|
||||||
|
<span>{status}</span>
|
||||||
|
</div>
|
||||||
|
{canEdit && <Pencil className="h-3 w-3 opacity-0 group-hover:opacity-70 transition-opacity" />}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -147,3 +147,86 @@ export const canEditPostStatus = (currentStatus: PlacementPostStatus): boolean =
|
|||||||
export const isAutomaticPostStatus = (status: PlacementPostStatus): boolean => {
|
export const isAutomaticPostStatus = (status: PlacementPostStatus): boolean => {
|
||||||
return AUTOMATIC_POST_STATUSES.has(status);
|
return AUTOMATIC_POST_STATUSES.has(status);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Status icon and color helpers
|
||||||
|
import {
|
||||||
|
CircleHelp,
|
||||||
|
FileText,
|
||||||
|
Clock,
|
||||||
|
DollarSign,
|
||||||
|
CheckCircle2,
|
||||||
|
XCircle,
|
||||||
|
AlertTriangle,
|
||||||
|
Send,
|
||||||
|
Calendar,
|
||||||
|
} from "lucide-react";
|
||||||
|
|
||||||
|
const StatusIconMap: Record<PlacementStatus, any> = {
|
||||||
|
"Без статуса": CircleHelp,
|
||||||
|
"Написать": FileText,
|
||||||
|
"Ждём ответа": Clock,
|
||||||
|
"Согласование условий": FileText,
|
||||||
|
"Оплатить": DollarSign,
|
||||||
|
"Оплачено": CheckCircle2,
|
||||||
|
"Отмена": XCircle,
|
||||||
|
"Не подходит цена": AlertTriangle,
|
||||||
|
"Неактуально": XCircle,
|
||||||
|
"Не отвечает": AlertTriangle,
|
||||||
|
};
|
||||||
|
|
||||||
|
const PostStatusIconMap: Record<PlacementPostStatus, any> = {
|
||||||
|
"Без статуса": CircleHelp,
|
||||||
|
"Отправить пост": Send,
|
||||||
|
"Согласование поста": FileText,
|
||||||
|
"Ожидание отложки": Clock,
|
||||||
|
"Запланирован": Calendar,
|
||||||
|
"Пост вышел": CheckCircle2,
|
||||||
|
"Размещение отработало - пост удалён": CheckCircle2,
|
||||||
|
"Размещение отработало - пост не удалён": CheckCircle2,
|
||||||
|
"Проверить - пост удалён раньше срока": AlertTriangle,
|
||||||
|
"Проверить - пост не вышел": Clock,
|
||||||
|
"Размещение отработало": CheckCircle2,
|
||||||
|
};
|
||||||
|
|
||||||
|
const StatusColorMap: Record<PlacementStatus, string> = {
|
||||||
|
"Без статуса": "bg-gray-100 text-gray-700 border-gray-200 dark:bg-gray-900/30 dark:text-gray-400 dark:border-gray-800",
|
||||||
|
"Написать": "bg-blue-100 text-blue-700 border-blue-200 dark:bg-blue-900/30 dark:text-blue-400 dark:border-blue-800",
|
||||||
|
"Ждём ответа": "bg-amber-100 text-amber-700 border-amber-200 dark:bg-amber-900/30 dark:text-amber-400 dark:border-amber-800",
|
||||||
|
"Согласование условий": "bg-purple-100 text-purple-700 border-purple-200 dark:bg-purple-900/30 dark:text-purple-400 dark:border-purple-800",
|
||||||
|
"Оплатить": "bg-green-100 text-green-700 border-green-200 dark:bg-green-900/30 dark:text-green-400 dark:border-green-800",
|
||||||
|
"Оплачено": "bg-emerald-100 text-emerald-700 border-emerald-200 dark:bg-emerald-900/30 dark:text-emerald-400 dark:border-emerald-800",
|
||||||
|
"Отмена": "bg-red-100 text-red-700 border-red-200 dark:bg-red-900/30 dark:text-red-400 dark:border-red-800",
|
||||||
|
"Не подходит цена": "bg-orange-100 text-orange-700 border-orange-200 dark:bg-orange-900/30 dark:text-orange-400 dark:border-orange-800",
|
||||||
|
"Неактуально": "bg-gray-100 text-gray-700 border-gray-200 dark:bg-gray-900/30 dark:text-gray-400 dark:border-gray-800",
|
||||||
|
"Не отвечает": "bg-red-100 text-red-700 border-red-200 dark:bg-red-900/30 dark:text-red-400 dark:border-red-800",
|
||||||
|
};
|
||||||
|
|
||||||
|
const PostStatusColorMap: Record<PlacementPostStatus, string> = {
|
||||||
|
"Без статуса": "bg-gray-100 text-gray-700 border-gray-200 dark:bg-gray-900/30 dark:text-gray-400 dark:border-gray-800",
|
||||||
|
"Отправить пост": "bg-blue-100 text-blue-700 border-blue-200 dark:bg-blue-900/30 dark:text-blue-400 dark:border-blue-800",
|
||||||
|
"Согласование поста": "bg-purple-100 text-purple-700 border-purple-200 dark:bg-purple-900/30 dark:text-purple-400 dark:border-purple-800",
|
||||||
|
"Ожидание отложки": "bg-amber-100 text-amber-700 border-amber-200 dark:bg-amber-900/30 dark:text-amber-400 dark:border-amber-800",
|
||||||
|
"Запланирован": "bg-cyan-100 text-cyan-700 border-cyan-200 dark:bg-cyan-900/30 dark:text-cyan-400 dark:border-cyan-800",
|
||||||
|
"Пост вышел": "bg-emerald-100 text-emerald-700 border-emerald-200 dark:bg-emerald-900/30 dark:text-emerald-400 dark:border-emerald-800",
|
||||||
|
"Размещение отработало - пост удалён": "bg-emerald-100 text-emerald-700 border-emerald-200 dark:bg-emerald-900/30 dark:text-emerald-400 dark:border-emerald-800",
|
||||||
|
"Размещение отработало - пост не удалён": "bg-emerald-100 text-emerald-700 border-emerald-200 dark:bg-emerald-900/30 dark:text-emerald-400 dark:border-emerald-800",
|
||||||
|
"Проверить - пост удалён раньше срока": "bg-orange-100 text-orange-700 border-orange-200 dark:bg-orange-900/30 dark:text-orange-400 dark:border-orange-800",
|
||||||
|
"Проверить - пост не вышел": "bg-red-100 text-red-700 border-red-200 dark:bg-red-900/30 dark:text-red-400 dark:border-red-800",
|
||||||
|
"Размещение отработало": "bg-emerald-100 text-emerald-700 border-emerald-200 dark:bg-emerald-900/30 dark:text-emerald-400 dark:border-emerald-800",
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getPlacementStatusIcon = (status: PlacementStatus): any => {
|
||||||
|
return StatusIconMap[status] || CircleHelp;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getPlacementStatusColor = (status: PlacementStatus): string => {
|
||||||
|
return StatusColorMap[status] || StatusColorMap["Без статуса"];
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getPlacementPostStatusIcon = (status: PlacementPostStatus): any => {
|
||||||
|
return PostStatusIconMap[status] || CircleHelp;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getPlacementPostStatusColor = (status: PlacementPostStatus): string => {
|
||||||
|
return PostStatusColorMap[status] || PostStatusColorMap["Без статуса"];
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user