chore: add missing multi-level editor for approval workflow, rename projects to campaings.
This commit is contained in:
@@ -3,12 +3,12 @@
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { mdiChevronLeft, mdiChevronRight } from '@mdi/js';
|
||||
import { useWorkspaceStore } from '@/features/workspaces/stores/workspaceStore.js';
|
||||
import { useProjectsStore } from '@/features/projects/stores/projectsStore.js';
|
||||
import { useCampaignsStore } from '@/features/campaigns/stores/campaignsStore.js';
|
||||
import { useContentItemsStore } from '@/features/content/stores/contentItemsStore.js';
|
||||
|
||||
const { t, locale } = useI18n();
|
||||
const workspaceStore = useWorkspaceStore();
|
||||
const projectsStore = useProjectsStore();
|
||||
const campaignsStore = useCampaignsStore();
|
||||
const contentItemsStore = useContentItemsStore();
|
||||
|
||||
const today = startOfDay(new Date());
|
||||
@@ -17,42 +17,35 @@
|
||||
|
||||
const contentStatusMeta = {
|
||||
Draft: { tone: 'production', readiness: 'building' },
|
||||
'In internal review': { tone: 'approval', readiness: 'approval' },
|
||||
'Changes requested internally': { tone: 'risk', readiness: 'rework' },
|
||||
'Internal changes in progress': { tone: 'production', readiness: 'building' },
|
||||
'Ready for client review': { tone: 'approval', readiness: 'approval' },
|
||||
'In client review': { tone: 'approval', readiness: 'approval' },
|
||||
'Changes requested by client': { tone: 'risk', readiness: 'rework' },
|
||||
'Client changes in progress': { tone: 'production', readiness: 'building' },
|
||||
'In production': { tone: 'production', readiness: 'building' },
|
||||
'In approval': { tone: 'approval', readiness: 'approval' },
|
||||
Approved: { tone: 'ready', readiness: 'ready' },
|
||||
'Ready to publish': { tone: 'ready', readiness: 'ready' },
|
||||
Scheduled: { tone: 'ready', readiness: 'scheduled' },
|
||||
Published: { tone: 'published', readiness: 'published' },
|
||||
Rejected: { tone: 'risk', readiness: 'blocked' },
|
||||
Archived: { tone: 'muted', readiness: 'archived' },
|
||||
};
|
||||
|
||||
const contentItemsByProjectId = computed(() => {
|
||||
const contentItemsByCampaignId = computed(() => {
|
||||
const grouped = new Map();
|
||||
|
||||
for (const item of contentItemsStore.items) {
|
||||
const existing = grouped.get(item.projectId) ?? [];
|
||||
const existing = grouped.get(item.campaignId) ?? [];
|
||||
existing.push(item);
|
||||
grouped.set(item.projectId, existing);
|
||||
grouped.set(item.campaignId, existing);
|
||||
}
|
||||
|
||||
return grouped;
|
||||
});
|
||||
|
||||
const calendarEntries = computed(() => {
|
||||
const projectEntries = projectsStore.projects
|
||||
.filter(project => project.endDate || project.startDate)
|
||||
.map(project => buildProjectEntry(project));
|
||||
const campaignEntries = campaignsStore.campaigns
|
||||
.filter(campaign => campaign.endDate || campaign.startDate)
|
||||
.map(campaign => buildCampaignEntry(campaign));
|
||||
|
||||
const contentEntries = contentItemsStore.items
|
||||
.filter(item => item.dueDate && item.status !== 'Archived')
|
||||
.filter(item => item.dueDate)
|
||||
.map(item => buildContentEntry(item));
|
||||
|
||||
return [...projectEntries, ...contentEntries].sort(sortByDate);
|
||||
return [...campaignEntries, ...contentEntries].sort(sortByDate);
|
||||
});
|
||||
|
||||
const entriesByDay = computed(() => {
|
||||
@@ -126,11 +119,11 @@
|
||||
});
|
||||
|
||||
const isLoading = computed(() =>
|
||||
workspaceStore.isLoading || projectsStore.isLoading || contentItemsStore.isLoading
|
||||
workspaceStore.isLoading || campaignsStore.isLoading || contentItemsStore.isLoading
|
||||
);
|
||||
|
||||
const pageError = computed(() =>
|
||||
workspaceStore.error || projectsStore.error || contentItemsStore.error
|
||||
workspaceStore.error || campaignsStore.error || contentItemsStore.error
|
||||
);
|
||||
|
||||
function buildDay(date, isOutsideMonth) {
|
||||
@@ -147,13 +140,13 @@
|
||||
|
||||
function buildContentEntry(item) {
|
||||
const statusMeta = contentStatusMeta[item.status] ?? { tone: 'production', readiness: 'building' };
|
||||
const project = projectsStore.projects.find(candidate => candidate.id === item.projectId);
|
||||
const campaign = campaignsStore.campaigns.find(candidate => candidate.id === item.campaignId);
|
||||
|
||||
return {
|
||||
id: item.id,
|
||||
type: 'content',
|
||||
title: item.title,
|
||||
subtitle: project?.name ?? t('dashboard.labels.unassignedProject'),
|
||||
subtitle: campaign?.name ?? t('dashboard.labels.unassignedCampaign'),
|
||||
scheduledAt: new Date(item.dueDate),
|
||||
dayKey: dateKey(item.dueDate),
|
||||
timeLabel: formatHour(item.dueDate),
|
||||
@@ -162,22 +155,22 @@
|
||||
};
|
||||
}
|
||||
|
||||
function buildProjectEntry(project) {
|
||||
const projectItems = contentItemsByProjectId.value.get(project.id) ?? [];
|
||||
const approvedCount = projectItems.filter(item => ['Approved', 'Ready to publish', 'Published'].includes(item.status)).length;
|
||||
function buildCampaignEntry(campaign) {
|
||||
const campaignItems = contentItemsByCampaignId.value.get(campaign.id) ?? [];
|
||||
const approvedCount = campaignItems.filter(item => ['Approved', 'Scheduled', 'Published'].includes(item.status)).length;
|
||||
|
||||
return {
|
||||
id: project.id,
|
||||
type: 'project',
|
||||
title: project.name,
|
||||
subtitle: projectItems.length
|
||||
? t('dashboard.projectProgress', { scheduled: projectItems.length, approved: approvedCount })
|
||||
id: campaign.id,
|
||||
type: 'campaign',
|
||||
title: campaign.name,
|
||||
subtitle: campaignItems.length
|
||||
? t('dashboard.campaignProgress', { scheduled: campaignItems.length, approved: approvedCount })
|
||||
: t('dashboard.readiness.missing'),
|
||||
scheduledAt: new Date(project.endDate ?? project.startDate),
|
||||
dayKey: dateKey(project.endDate ?? project.startDate),
|
||||
scheduledAt: new Date(campaign.endDate ?? campaign.startDate),
|
||||
dayKey: dateKey(campaign.endDate ?? campaign.startDate),
|
||||
timeLabel: t('dashboard.campaignDeadline'),
|
||||
tone: projectItems.length ? 'project' : 'risk',
|
||||
route: { name: 'campaign-detail', params: { projectId: project.id } },
|
||||
tone: campaignItems.length ? 'campaign' : 'risk',
|
||||
route: { name: 'campaign-detail', params: { campaignId: campaign.id } },
|
||||
};
|
||||
}
|
||||
|
||||
@@ -560,7 +553,7 @@
|
||||
border-color: rgba(220, 38, 38, 0.16);
|
||||
}
|
||||
|
||||
.calendar-entry.project {
|
||||
.calendar-entry.campaign {
|
||||
background: #f8fafc;
|
||||
border-color: rgba(71, 85, 105, 0.18);
|
||||
border-style: dashed;
|
||||
|
||||
Reference in New Issue
Block a user