refactor(posts): replace status string literals with PostStatus enum
Introduce resources/js/types/post.ts mirroring App\Enums\Post\Status and App\Enums\PostPlatform\Status. Replace inline string comparisons across Edit.vue, Show.vue, PostEditorHeader.vue and ScheduleTab.vue.
This commit is contained in:
parent
99d1770c6c
commit
2902506f35
5 changed files with 53 additions and 21 deletions
|
|
@ -5,6 +5,7 @@ import { computed } from 'vue';
|
|||
import PickTimePopover from '@/components/posts/PickTimePopover.vue';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';
|
||||
import { PostStatus } from '@/types/post';
|
||||
|
||||
interface Props {
|
||||
post: { status: string };
|
||||
|
|
@ -27,9 +28,12 @@ const emit = defineEmits<{
|
|||
(e: 'submit', status: string): void;
|
||||
}>();
|
||||
|
||||
const isReadOnly = computed(() => ['publishing', 'published', 'partially_published'].includes(props.post.status));
|
||||
const isScheduled = computed(() => props.post.status === 'scheduled');
|
||||
const isPublished = computed(() => ['published', 'partially_published'].includes(props.post.status));
|
||||
const READONLY_STATUSES: readonly string[] = [PostStatus.Publishing, PostStatus.Published, PostStatus.PartiallyPublished];
|
||||
const PUBLISHED_STATUSES: readonly string[] = [PostStatus.Published, PostStatus.PartiallyPublished];
|
||||
|
||||
const isReadOnly = computed(() => READONLY_STATUSES.includes(props.post.status));
|
||||
const isScheduled = computed(() => props.post.status === PostStatus.Scheduled);
|
||||
const isPublished = computed(() => PUBLISHED_STATUSES.includes(props.post.status));
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/comp
|
|||
import { getPlatformLabel, getPlatformLogo } from '@/composables/usePlatformLogo';
|
||||
import { Platform } from '@/enums/platform';
|
||||
import type { PinterestBoard } from '@/types';
|
||||
import { PostPlatformStatus } from '@/types/post';
|
||||
|
||||
interface SocialAccount {
|
||||
id: string;
|
||||
|
|
@ -199,10 +200,10 @@ const getPlatformAvatar = (pp: PostPlatform): string | null =>
|
|||
>
|
||||
<IconAlertCircle class="h-2.5 w-2.5" />
|
||||
</Badge>
|
||||
<Badge v-else-if="pp.status === 'published'" variant="success" class="absolute -top-1 -right-1 h-4 w-4 p-0">
|
||||
<Badge v-else-if="pp.status === PostPlatformStatus.Published" variant="success" class="absolute -top-1 -right-1 h-4 w-4 p-0">
|
||||
<IconCircleCheck class="h-2.5 w-2.5" />
|
||||
</Badge>
|
||||
<Badge v-else-if="pp.status === 'failed'" variant="destructive" class="absolute -top-1 -right-1 h-4 w-4 p-0 text-[9px]">!</Badge>
|
||||
<Badge v-else-if="pp.status === PostPlatformStatus.Failed" variant="destructive" class="absolute -top-1 -right-1 h-4 w-4 p-0 text-[9px]">!</Badge>
|
||||
</div>
|
||||
<span
|
||||
class="line-clamp-2 text-center text-xs leading-tight"
|
||||
|
|
@ -226,7 +227,7 @@ const getPlatformAvatar = (pp: PostPlatform): string | null =>
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="postPlatforms.some(pp => pp.status !== 'pending')">
|
||||
<div v-if="postPlatforms.some(pp => pp.status !== PostPlatformStatus.Pending)">
|
||||
<p class="mb-2 text-[11px] font-black uppercase tracking-widest text-foreground/60">
|
||||
{{ $t('posts.edit.platform_status') }}
|
||||
</p>
|
||||
|
|
@ -243,12 +244,12 @@ const getPlatformAvatar = (pp: PostPlatform): string | null =>
|
|||
<span class="text-sm font-bold text-foreground">{{ getPlatformDisplayName(pp) }}</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<Badge v-if="pp.status === 'published'" variant="success">{{ $t('posts.edit.status.published') }}</Badge>
|
||||
<Badge v-else-if="pp.status === 'publishing'" variant="warning">
|
||||
<Badge v-if="pp.status === PostPlatformStatus.Published" variant="success">{{ $t('posts.edit.status.published') }}</Badge>
|
||||
<Badge v-else-if="pp.status === PostPlatformStatus.Publishing" variant="warning">
|
||||
<IconLoader2 class="size-3 animate-spin" />
|
||||
{{ $t('posts.edit.status.publishing') }}
|
||||
</Badge>
|
||||
<Badge v-else-if="pp.status === 'failed'" variant="destructive">{{ $t('posts.edit.status.failed') }}</Badge>
|
||||
<Badge v-else-if="pp.status === PostPlatformStatus.Failed" variant="destructive">{{ $t('posts.edit.status.failed') }}</Badge>
|
||||
<a
|
||||
v-if="pp.platform_url"
|
||||
:href="pp.platform_url"
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import dayjs from '@/dayjs';
|
|||
import debounce from '@/debounce';
|
||||
import { ContentType } from '@/enums/content-type';
|
||||
import { Platform } from '@/enums/platform';
|
||||
import { PostStatus } from '@/types/post';
|
||||
import AppLayout from '@/layouts/AppLayout.vue';
|
||||
import { destroy as destroyPost, update as updatePost } from '@/routes/app/posts';
|
||||
import type { PinterestBoard } from '@/types';
|
||||
|
|
@ -98,10 +99,15 @@ const props = defineProps<{
|
|||
}>();
|
||||
|
||||
const post = computed(() => props.post);
|
||||
// Terminal states the user cannot recover from — delete, navigate, but never edit.
|
||||
const isReadOnly = computed(() => ['publishing', 'published', 'partially_published', 'failed'].includes(post.value.status));
|
||||
const isPublishing = computed(() => post.value.status === 'publishing');
|
||||
const isScheduled = computed(() => post.value.status === 'scheduled');
|
||||
const READONLY_STATUSES: readonly string[] = [
|
||||
PostStatus.Publishing,
|
||||
PostStatus.Published,
|
||||
PostStatus.PartiallyPublished,
|
||||
PostStatus.Failed,
|
||||
];
|
||||
const isReadOnly = computed(() => READONLY_STATUSES.includes(post.value.status));
|
||||
const isPublishing = computed(() => post.value.status === PostStatus.Publishing);
|
||||
const isScheduled = computed(() => post.value.status === PostStatus.Scheduled);
|
||||
// Locked states — terminal + scheduled. Field edits and auto-save suppressed;
|
||||
// user must unschedule to re-enter draft and edit.
|
||||
const isLocked = computed(() => isReadOnly.value || isScheduled.value);
|
||||
|
|
@ -345,7 +351,7 @@ const getLocalSchedule = () => {
|
|||
return dayjs.utc(post.value.scheduled_at).local().format('YYYY-MM-DDTHH:mm:00');
|
||||
};
|
||||
const scheduledDateTime = ref(getLocalSchedule());
|
||||
const hasPickedTime = ref(post.value.status === 'scheduled' && !! post.value.scheduled_at);
|
||||
const hasPickedTime = ref(post.value.status === PostStatus.Scheduled && !! post.value.scheduled_at);
|
||||
|
||||
const pickTimeLabel = computed(() => {
|
||||
if (! hasPickedTime.value || ! scheduledDateTime.value) {
|
||||
|
|
@ -466,7 +472,7 @@ onUnmounted(() => {
|
|||
debouncedSave.cancel();
|
||||
});
|
||||
|
||||
const submit = (status: string = 'scheduled') => {
|
||||
const submit = (status: string = PostStatus.Scheduled) => {
|
||||
if (isSubmitting.value || isReadOnly.value) return;
|
||||
debouncedSave.cancel();
|
||||
|
||||
|
|
@ -503,7 +509,7 @@ const unschedulePost = () => {
|
|||
debouncedSave.cancel();
|
||||
scheduledDateTime.value = '';
|
||||
hasPickedTime.value = false;
|
||||
submit('draft');
|
||||
submit(PostStatus.Draft);
|
||||
};
|
||||
|
||||
// Echo: listen for real-time platform status updates.
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import { getPlatformStatusConfig, getPostStatusConfig } from '@/composables/useP
|
|||
import dayjs from '@/dayjs';
|
||||
import AppLayout from '@/layouts/AppLayout.vue';
|
||||
import { index as postsIndex } from '@/routes/app/posts';
|
||||
import { PostPlatformStatus, PostStatus } from '@/types/post';
|
||||
|
||||
interface MediaItem {
|
||||
id: string;
|
||||
|
|
@ -73,7 +74,7 @@ const props = defineProps<{
|
|||
|
||||
const enabledPlatforms = computed(() => props.post.platforms.filter((pp) => pp.enabled));
|
||||
|
||||
const isPublishing = computed(() => props.post.status === 'publishing');
|
||||
const isPublishing = computed(() => props.post.status === PostStatus.Publishing);
|
||||
|
||||
const postStatus = computed(() => getPostStatusConfig(props.post.status));
|
||||
|
||||
|
|
@ -252,11 +253,11 @@ usePostEcho(props.post.id, '.post.platform.status.updated', () => {
|
|||
<component
|
||||
:is="getPlatformStatusConfig(pp.status).icon"
|
||||
class="size-3"
|
||||
:class="pp.status === 'publishing' ? 'animate-spin' : ''"
|
||||
:class="pp.status === PostPlatformStatus.Publishing ? 'animate-spin' : ''"
|
||||
/>
|
||||
{{ getPlatformStatusConfig(pp.status).label }}
|
||||
</Badge>
|
||||
<TooltipProvider v-if="pp.status === 'published' && pp.platform_url" :delay-duration="200">
|
||||
<TooltipProvider v-if="pp.status === PostPlatformStatus.Published && pp.platform_url" :delay-duration="200">
|
||||
<Tooltip>
|
||||
<TooltipTrigger as-child>
|
||||
<a
|
||||
|
|
@ -276,7 +277,7 @@ usePostEcho(props.post.id, '.post.platform.status.updated', () => {
|
|||
|
||||
<!-- Failed: error message -->
|
||||
<div
|
||||
v-if="pp.status === 'failed' && pp.error_message"
|
||||
v-if="pp.status === PostPlatformStatus.Failed && pp.error_message"
|
||||
class="border-t-2 border-foreground/10 bg-rose-50 px-4 py-3 text-xs font-semibold text-rose-700"
|
||||
>
|
||||
{{ pp.error_message }}
|
||||
|
|
@ -284,7 +285,7 @@ usePostEcho(props.post.id, '.post.platform.status.updated', () => {
|
|||
|
||||
<!-- Published: metrics -->
|
||||
<PostPlatformMetrics
|
||||
v-if="pp.status === 'published'"
|
||||
v-if="pp.status === PostPlatformStatus.Published"
|
||||
:post-id="post.id"
|
||||
:post-platform-id="pp.id"
|
||||
/>
|
||||
|
|
|
|||
20
resources/js/types/post.ts
Normal file
20
resources/js/types/post.ts
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
export const PostStatus = {
|
||||
Draft: 'draft',
|
||||
Scheduled: 'scheduled',
|
||||
Publishing: 'publishing',
|
||||
Published: 'published',
|
||||
PartiallyPublished: 'partially_published',
|
||||
Failed: 'failed',
|
||||
} as const;
|
||||
|
||||
export type PostStatusValue = (typeof PostStatus)[keyof typeof PostStatus];
|
||||
|
||||
export const PostPlatformStatus = {
|
||||
Pending: 'pending',
|
||||
Publishing: 'publishing',
|
||||
Published: 'published',
|
||||
Failed: 'failed',
|
||||
Retrying: 'retrying',
|
||||
} as const;
|
||||
|
||||
export type PostPlatformStatusValue = (typeof PostPlatformStatus)[keyof typeof PostPlatformStatus];
|
||||
Loading…
Reference in a new issue