Add agency-only schedule fields and queue for pipeline creatives.
Approved pieces can be timed for IG/FB from the agency board; cron queues due jobs and calendar uses scheduled_at. Meta publish comes next. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
56
src/lib/pipeline-schedule.ts
Normal file
56
src/lib/pipeline-schedule.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
/** Agency scheduling helpers for creative_pipeline. */
|
||||
|
||||
export const PUBLISH_CHANNELS = ['instagram', 'facebook'] as const;
|
||||
export type PublishChannel = (typeof PUBLISH_CHANNELS)[number];
|
||||
|
||||
export const PUBLISH_STATUSES = [
|
||||
'idle',
|
||||
'queued',
|
||||
'publishing',
|
||||
'published',
|
||||
'failed',
|
||||
] as const;
|
||||
export type PublishStatus = (typeof PUBLISH_STATUSES)[number];
|
||||
|
||||
export function normalizeChannels(raw: unknown): PublishChannel[] {
|
||||
const list = Array.isArray(raw)
|
||||
? raw.map((x) => String(x).toLowerCase().trim())
|
||||
: typeof raw === 'string'
|
||||
? raw.split(',').map((x) => x.toLowerCase().trim())
|
||||
: [];
|
||||
const out = PUBLISH_CHANNELS.filter((c) => list.includes(c));
|
||||
return out.length ? [...out] : ['instagram', 'facebook'];
|
||||
}
|
||||
|
||||
/** Parse datetime-local or ISO into timestamptz ISO, or null to clear. */
|
||||
export function parseScheduledAt(raw: unknown): string | null | undefined {
|
||||
if (raw === null) return null;
|
||||
if (raw === undefined) return undefined;
|
||||
if (typeof raw !== 'string') return undefined;
|
||||
const t = raw.trim();
|
||||
if (!t) return null;
|
||||
const d = new Date(t);
|
||||
if (Number.isNaN(d.getTime())) return undefined;
|
||||
return d.toISOString();
|
||||
}
|
||||
|
||||
export function toDatetimeLocalValue(iso?: string | null): string {
|
||||
if (!iso) return '';
|
||||
const d = new Date(iso);
|
||||
if (Number.isNaN(d.getTime())) return '';
|
||||
const pad = (n: number) => String(n).padStart(2, '0');
|
||||
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}`;
|
||||
}
|
||||
|
||||
export function scheduleLabel(iso?: string | null): string | null {
|
||||
if (!iso) return null;
|
||||
const d = new Date(iso);
|
||||
if (Number.isNaN(d.getTime())) return null;
|
||||
return d.toLocaleString('es-ES', {
|
||||
weekday: 'short',
|
||||
day: 'numeric',
|
||||
month: 'short',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user