Add real workspace channels
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
import { computed, onBeforeUnmount, reactive, watch } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { useSessionStorage } from '@vueuse/core';
|
||||
import { mdiArrowLeft } from '@mdi/js';
|
||||
import AppAvatar from '@/components/AppAvatar.vue';
|
||||
import { useChannelsStore } from '@/features/channels/stores/channelsStore.js';
|
||||
import { useClientsStore } from '@/features/clients/stores/clientsStore.js';
|
||||
@@ -332,6 +333,23 @@
|
||||
commentForm.body = '';
|
||||
}
|
||||
|
||||
async function navigateBackToContent() {
|
||||
const returnTo = typeof route.query.returnTo === 'string' ? route.query.returnTo : '';
|
||||
const previousPath = router.options.history.state.back;
|
||||
|
||||
if (returnTo.startsWith('/app/content')) {
|
||||
await router.push(returnTo);
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof previousPath === 'string' && previousPath.startsWith('/app/content')) {
|
||||
router.back();
|
||||
return;
|
||||
}
|
||||
|
||||
await router.push({ name: 'content-items' });
|
||||
}
|
||||
|
||||
function formatDateTime(value) {
|
||||
return value ? new Date(value).toLocaleString() : '';
|
||||
}
|
||||
@@ -373,6 +391,15 @@
|
||||
|
||||
<template>
|
||||
<section class="editor-shell">
|
||||
<button
|
||||
class="back-button"
|
||||
type="button"
|
||||
@click="navigateBackToContent"
|
||||
>
|
||||
<v-icon :icon="mdiArrowLeft" />
|
||||
Back to content
|
||||
</button>
|
||||
|
||||
<div
|
||||
v-if="!isCreateMode && detailStore.isLoading"
|
||||
class="page-message"
|
||||
@@ -838,9 +865,22 @@
|
||||
color: #172033;
|
||||
}
|
||||
|
||||
.back-button,
|
||||
.primary-button,
|
||||
.secondary-button {
|
||||
@apply inline-flex items-center justify-center rounded-full px-5 py-3 text-sm font-bold transition;
|
||||
@apply inline-flex items-center justify-center gap-2 rounded-full px-5 py-3 text-sm font-bold transition;
|
||||
}
|
||||
|
||||
.back-button {
|
||||
@apply w-fit border;
|
||||
background: rgba(255, 255, 255, 0.88);
|
||||
border-color: rgba(23, 32, 51, 0.12);
|
||||
color: #172033;
|
||||
}
|
||||
|
||||
.back-button:hover {
|
||||
background: #172033;
|
||||
color: #fffaf2;
|
||||
}
|
||||
|
||||
.primary-button {
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
<script setup>
|
||||
import { computed, ref } from 'vue';
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { mdiChevronLeft, mdiChevronRight } from '@mdi/js';
|
||||
import { useCampaignsStore } from '@/features/campaigns/stores/campaignsStore.js';
|
||||
import { useContentItemsStore } from '@/features/content/stores/contentItemsStore.js';
|
||||
|
||||
const { t, locale } = useI18n();
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const campaignsStore = useCampaignsStore();
|
||||
const contentItemsStore = useContentItemsStore();
|
||||
|
||||
const today = startOfDay(new Date());
|
||||
const viewMode = ref('month');
|
||||
const cursorDate = ref(today);
|
||||
const viewMode = ref(parseViewMode(route.query.view));
|
||||
const cursorDate = ref(parseCursorDate(route.query.date, today));
|
||||
|
||||
const contentStatusMeta = {
|
||||
Draft: { tone: 'production' },
|
||||
@@ -165,7 +168,7 @@
|
||||
dayKey: dateKey(item.dueDate),
|
||||
timeLabel: formatHour(item.dueDate),
|
||||
tone: statusMeta.tone,
|
||||
route: { name: 'content-item-detail', params: { id: item.id } },
|
||||
route: { name: 'content-item-detail', params: { id: item.id }, query: { returnTo: route.fullPath } },
|
||||
};
|
||||
}
|
||||
|
||||
@@ -275,6 +278,45 @@
|
||||
function sortByDate(left, right) {
|
||||
return left.scheduledAt.getTime() - right.scheduledAt.getTime();
|
||||
}
|
||||
|
||||
function parseViewMode(value) {
|
||||
return ['month', 'week', 'upcoming'].includes(value) ? value : 'month';
|
||||
}
|
||||
|
||||
function parseCursorDate(value, fallback) {
|
||||
if (typeof value !== 'string') {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
const parsed = new Date(`${value}T00:00:00`);
|
||||
return Number.isNaN(parsed.getTime()) ? fallback : startOfDay(parsed);
|
||||
}
|
||||
|
||||
watch(
|
||||
() => route.query,
|
||||
query => {
|
||||
viewMode.value = parseViewMode(query.view);
|
||||
cursorDate.value = parseCursorDate(query.date, today);
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => [viewMode.value, dateKey(cursorDate.value)],
|
||||
([view, date]) => {
|
||||
if (route.query.view === view && route.query.date === date) {
|
||||
return;
|
||||
}
|
||||
|
||||
router.replace({
|
||||
name: 'content-items',
|
||||
query: {
|
||||
...route.query,
|
||||
view,
|
||||
date,
|
||||
},
|
||||
});
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -429,7 +471,7 @@
|
||||
<router-link
|
||||
v-for="item in upcomingItems"
|
||||
:key="item.id"
|
||||
:to="{ name: 'content-item-detail', params: { id: item.id } }"
|
||||
:to="{ name: 'content-item-detail', params: { id: item.id }, query: { returnTo: route.fullPath } }"
|
||||
class="item-card"
|
||||
>
|
||||
<div class="version-chip">{{ item.currentRevisionLabel }}</div>
|
||||
|
||||
Reference in New Issue
Block a user