feat: use channel portraits across app
All checks were successful
deploy-socialize / image (push) Successful in 50s
deploy-socialize / deploy (push) Successful in 20s

This commit is contained in:
2026-05-09 13:33:46 -04:00
parent afcdd1ace1
commit 01a44abc9c
3 changed files with 67 additions and 86 deletions

View File

@@ -3,7 +3,6 @@
import { useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n';
import { useWorkspaceStore } from '@/features/workspaces/stores/workspaceStore.js';
import { useContentItemsStore } from '@/features/content/stores/contentItemsStore.js';
import { useChannelsStore } from '@/features/channels/stores/channelsStore.js';
import {
mdiClose,
@@ -24,7 +23,6 @@
const route = useRoute();
const { t } = useI18n();
const workspaceStore = useWorkspaceStore();
const contentItemsStore = useContentItemsStore();
const channelsStore = useChannelsStore();
const isCreateFormVisible = ref(false);
@@ -55,12 +53,10 @@
channelsStore.channels
.filter(channel => channel.network)
.map(channel => {
const metrics = buildMetrics(channel.name);
const workspace = workspaceStore.workspaces.find(candidate => candidate.id === channel.workspaceId);
return {
...channel,
...metrics,
workspaceName: workspace?.name ?? t('nav.noWorkspace'),
};
})
@@ -80,27 +76,8 @@
portraitUrl: form.portraitUrl.trim(),
bannerUrl: form.bannerUrl.trim(),
workspaceName: workspaceStore.activeWorkspace?.name ?? t('nav.noWorkspace'),
scheduled: 0,
readyCount: 0,
blockedCount: 0,
nextDueDate: null,
}));
function buildMetrics(channelName) {
const matches = contentItemsStore.items.filter(item =>
parseTargets(item.publicationTargets).some(target => target.toLowerCase() === channelName.toLowerCase())
);
return {
scheduled: matches.length,
nextDueDate: matches
.filter(item => item.dueDate)
.sort((left, right) => new Date(left.dueDate).getTime() - new Date(right.dueDate).getTime())[0]?.dueDate ?? null,
readyCount: matches.filter(item => ['Approved', 'Scheduled', 'Published'].includes(item.status)).length,
blockedCount: matches.filter(item => item.status === 'In approval').length,
};
}
function resetForm() {
form.name = '';
form.network = activeNetwork.value;
@@ -172,13 +149,6 @@
}
}
function parseTargets(value) {
return (value ?? '')
.split(/[,\n]+/)
.map(target => target.trim())
.filter(Boolean);
}
function channelHandle(channel) {
const rawHandle = channel.handle || channel.name || channel.network;
@@ -484,25 +454,7 @@
</div>
</div>
<div class="channel-metrics">
<div>
<small>{{ t('channels.metrics.scheduled') }}</small>
<strong>{{ channel.scheduled }}</strong>
</div>
<div>
<small>{{ t('channels.metrics.ready') }}</small>
<strong>{{ channel.readyCount }}</strong>
</div>
<div>
<small>{{ t('channels.metrics.blocked') }}</small>
<strong>{{ channel.blockedCount }}</strong>
</div>
</div>
<div class="channel-footer">
<span>{{ t('channels.nextDue') }}</span>
<em>{{ channel.nextDueDate ? new Date(channel.nextDueDate).toLocaleDateString() : t('channels.noScheduled') }}</em>
</div>
<p>{{ channel.workspaceName }}</p>
</article>
</div>
@@ -531,9 +483,6 @@
.header p,
.channel-profile-row span,
.channel-footer span,
.channel-footer em,
.channel-metrics small,
.page-message,
.empty-state span {
@apply text-sm leading-6 not-italic;
@@ -606,8 +555,7 @@
.panel-header strong,
.field,
.channel-profile-row strong,
.channel-metrics strong {
.channel-profile-row strong {
color: var(--app-color-on-surface);
}
@@ -649,10 +597,6 @@
@apply flex justify-end gap-3;
}
.channel-footer {
@apply flex items-center justify-between gap-4;
}
.channel-preview-card {
@apply overflow-hidden p-0;
}
@@ -709,7 +653,7 @@
}
.channel-preview-card > p {
@apply px-5 text-sm font-semibold;
@apply px-5 pb-5 text-sm font-semibold;
color: var(--app-text-muted);
}
@@ -745,25 +689,6 @@
background: linear-gradient(135deg, #0f766e, #2563eb);
}
.channel-metrics {
@apply mx-5 grid grid-cols-3 gap-3 rounded-[1rem] border p-4;
background: var(--app-color-on-primary);
border-color: var(--app-border-subtle);
}
.channel-metrics div {
@apply flex flex-col gap-1;
}
.channel-metrics strong {
@apply text-2xl font-black;
}
.channel-footer {
@apply border-t px-5 py-4;
border-color: var(--app-border-subtle);
}
.page-message {
@apply rounded-[1.25rem] border p-4 font-medium;
background: rgba(255, 255, 255, 0.84);