Step 6 — Frontend: Types, Store, Shared Components
Files:
front-end/src/types/posts.tsfront-end/src/stores/posts.tsfront-end/src/components/partials/lifestyle/LifestyleContentTab.vuefront-end/src/components/pages/campaign/CampaignPosts.vuefront-end/src/components/partials/posts/PostDetailModal.vue
Prerequisites: Step 1 — DB Migration applied
What This Does
Removes all scheduled / scheduledDate references from shared frontend types, the posts store, and three components. After this step, nothing in the frontend reads or writes customer_posts.scheduled.
6.1 — front-end/src/types/posts.ts
Remove scheduled: string from the Post type and scheduledDate: Date | null from PostData.
Find:
export type Post = {
id: number
title: string
html: string
platforms: string[]
scheduled: string
status: 'new' | 'approved' | 'draft' | 'removed' | 'sent'
Replace with:
export type Post = {
id: number
title: string
html: string
platforms: string[]
status: 'new' | 'approved' | 'draft' | 'removed' | 'sent'
Find and remove the scheduledDate field from PostData:
export interface PostData {
scheduledDate: Date | null
status: string
title: string
}
Replace with:
export interface PostData {
status: string
title: string
}
6.2 — front-end/src/stores/posts.ts
Remove scheduled from the POST_CANONICAL_SELECT constant.
Find:
const POST_CANONICAL_SELECT = `
id, title, platforms, scheduled, sent_at, status, created_at, updated_at,
prompt, active, customer_id, campaign_id, email_list_id, generation_reason,
customer:customer_customer(id, name),
campaign:customer_campaign(id, name, customer_id)
`
Replace with:
const POST_CANONICAL_SELECT = `
id, title, platforms, sent_at, status, created_at, updated_at,
prompt, active, customer_id, campaign_id, email_list_id, generation_reason,
customer:customer_customer(id, name),
campaign:customer_campaign(id, name, customer_id)
`
6.3 — front-end/src/components/partials/lifestyle/LifestyleContentTab.vue
a) Fix postsByDate computed (line ~54) — remove post.scheduled from the date reference:
Find:
const ref = post.sent_at || post.scheduled || post.created_at
Replace with:
const ref = post.sent_at || post.created_at
b) Fix dayOfWeekCounts computed (line ~70) — remove p.scheduled:
Find:
const ref = p.sent_at || p.scheduled
Replace with:
const ref = p.sent_at
c) Fix the footer line referencing sent/scheduled count (line ~345):
Find:
{{ posts.filter((p) => p.sent_at || p.scheduled).length }}
scheduled/sent posts
Replace with:
{{ posts.filter((p) => p.sent_at).length }}
sent posts
d) Remove the scheduled column from columns (line ~133):
Find:
{
key: 'scheduled',
label: 'Scheduled',
sortable: true,
colClass: 'hidden md:table-cell',
},
Delete this entire object from the columns array.
e) Remove #cell-scheduled template slot (lines ~519-521):
Find and delete:
<template #cell-scheduled="{ row }">
<span v-if="row.scheduled" class="text-muted-foreground">
{{ dayjs(row.scheduled).format('MMM D, YYYY h:mm A') }}
</span>
<span v-else class="text-muted-foreground">—</span>
</template>
f) Remove scheduled from the Supabase select query (line ~187):
Find:
;`id, title, html, platforms, scheduled, sent_at, status, created_at, updated_at, prompt, active, generation_reason, context_sources`
Replace with:
;`id, title, html, platforms, sent_at, status, created_at, updated_at, prompt, active, generation_reason, context_sources`
6.4 — front-end/src/components/pages/campaign/CampaignPosts.vue
a) Remove scheduled column from columns array:
Find:
{ key: 'scheduled', label: 'Scheduled', sortable: true, colClass: 'hidden md:table-cell' },
Delete this line.
b) Remove #cell-scheduled template slot:
Find and delete:
<template #cell-scheduled="{ row }">
{{ row.scheduled ? new Date(row.scheduled).toLocaleString() : 'Not Scheduled' }}
</template>
c) Fix the status cell that checks row.scheduled:
Find:
{{ _.startCase(row.scheduled && row.status === 'approved' ? 'scheduled' : row.status) }}
Replace with:
{{ _.startCase(row.status) }}
6.5 — front-end/src/components/partials/posts/PostDetailModal.vue
This has the most changes. Work through them carefully.
a) Remove scheduled?: string from the Post interface (line ~22):
Find:
interface Post {
id: number
title: string
platforms: string[]
scheduled?: string
status:
Replace with:
interface Post {
id: number
title: string
platforms: string[]
status:
b) Remove scheduled?: string from the PostContent interface (line ~61):
Find:
title?: string
subtitle?: string | null
platforms?: string[]
scheduled?: string
status?: string
Replace with:
title?: string
subtitle?: string | null
platforms?: string[]
status?: string
c) Remove scheduledDate: null from viewPostData initial value (line ~99):
Find:
const viewPostData = ref<any>({
scheduledDate: null,
status: 'new',
title: '',
active: true,
})
Replace with:
const viewPostData = ref<any>({
status: 'new',
title: '',
active: true,
})
d) Remove 'scheduled' from viewStatusOptions (line ~109):
Find:
const viewStatusOptions = [
'new',
'pending_review',
'revision_requested',
'approved',
'scheduled',
'sent',
Replace with:
const viewStatusOptions = [
'new',
'pending_review',
'revision_requested',
'approved',
'sent',
e) Replace the savePost logic that enforces the scheduled/date invariant (lines ~510-522):
Find:
const { title } = viewPostData.value
let { status, scheduledDate } = viewPostData.value
// Enforce status ↔ scheduled-date invariant at save time:
// • status !== 'scheduled' → clear any stale date (status wins)
// • status === 'scheduled' with no date → revert to 'approved'
if (status !== 'scheduled') {
scheduledDate = null
} else if (!scheduledDate) {
// 'scheduled' without a date is invalid — revert to approved
status = 'approved'
}
const updates: Record<string, unknown> = { scheduled: scheduledDate, status, title }
Replace with:
const { title, status } = viewPostData.value
const updates: Record<string, unknown> = { status, title }
f) Remove scheduledDate assignment in openPostModal (line ~837):
Find:
viewPostData.value.scheduledDate = post.scheduled ? new Date(post.scheduled) : null
viewPostData.value.status = post.status
Replace with:
viewPostData.value.status = post.status
g) Remove scheduledDate: null from closePostModal reset (line ~880):
Find:
viewPostData.value = {
scheduledDate: null,
status: 'new',
title: '',
active: true,
}
Replace with:
viewPostData.value = {
status: 'new',
title: '',
active: true,
}
h) Delete the watch that auto-promotes status when scheduledDate changes (line ~958):
Find and delete:
// When the user picks a scheduled date, auto-promote status to 'scheduled'
// so the save-time invariant (status !== 'scheduled' → clear date) doesn't drop it.
watch(
() => viewPostData.value.scheduledDate,
(newDate) => {
if (newDate && viewPostData.value.status !== 'scheduled') {
viewPostData.value.status = 'scheduled'
}
}
)
i) Check if there is a date-picker UI element in the template for scheduledDate — search the template section for scheduledDate and delete any date-picker input or v-model="viewPostData.scheduledDate" binding if present.
6.6 — Verify
cd front-end
pnpm test:tsc
# Should report 0 errors related to `scheduled` or `scheduledDate`
pnpm test:unit
✅ Done
Proceed to Step 7 — ClientOverview Calendar.