trypost/resources/js/components/posts/previews/PlatformPreview.vue
Paulo Castellano 1af705f3fd
Localize calendar date pickers to the active UI locale (#234)
* Localize calendar date pickers to the active UI locale.

Pass the Inertia locale into Reka calendars, translate a11y labels, and use dayjs LL/LLL for DatePicker display text.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Localize remaining dayjs date displays across the UI.

Route list/calendar/preview timestamps through localized LL/LLL helpers so formats follow the active UI locale instead of English or Portuguese-locked patterns.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Use scheduled-or-now timestamps in platform previews.

Drive preview labels from the post schedule when set, localize Discord without dayjs calendar(), and expose a single formatPreviewPostedAt helper.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Fix preview schedule wiring and Discord/Facebook timestamp labels.

Restore hasPickedTime from any saved scheduled_at, keep time on non-today Discord labels, and use a localized just-now fallback for unschedled Facebook previews.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Fix API key expiry day shift and tighten calendar range titles.

Format date-only expiry in UTC calendar days, and use compact dayjs titles for calendar day/week headers.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Replace frontend date source greps with Inertia API key assertions.

Drop the Vue/TS file scanner and assert expiry calendar days through ApiKeyController props instead.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Localize calendar week titles with day-first dayjs formats.

Avoid English month-day order in week headers and chart axis labels so locales like pt-BR keep natural day-first dates.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Split preview timestamp formatting into named platform helpers.

Replace the style-switch formatPreviewPostedAt with clear per-platform helpers so call sites read as formatDiscordPreview / formatXPreview / etc.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-05 21:02:34 -03:00

92 lines
2.5 KiB
Vue

<script setup lang="ts">
import { computed } from 'vue';
import type { MediaItem } from '@/types/media';
import BlueskyPreview from './BlueskyPreview.vue';
import DiscordPreview from './DiscordPreview.vue';
import FacebookPreview from './FacebookPreview.vue';
import InstagramPreview from './InstagramPreview.vue';
import LinkedInPreview from './LinkedInPreview.vue';
import MastodonPreview from './MastodonPreview.vue';
import PinterestPreview from './PinterestPreview.vue';
import TelegramPreview from './TelegramPreview.vue';
import ThreadsPreview from './ThreadsPreview.vue';
import TikTokPreview from './TikTokPreview.vue';
import XPreview from './XPreview.vue';
import YouTubePreview from './YouTubePreview.vue';
interface SocialAccount {
id: string;
platform: string;
display_name: string;
username: string;
avatar_url: string | null;
}
interface Props {
platform: string;
socialAccount: SocialAccount | null | undefined;
content: string;
media: MediaItem[];
contentType?: string;
meta?: Record<string, any>;
/** Local scheduled datetime (datetime-local); falls back to now in previews. */
postedAt?: string | null;
}
const props = defineProps<Props>();
const resolvedSocialAccount = computed((): SocialAccount => props.socialAccount ?? {
id: '',
platform: props.platform,
display_name: '',
username: '',
avatar_url: null,
});
const previewComponent = computed(() => {
switch (props.platform) {
case 'linkedin':
case 'linkedin-page':
return LinkedInPreview;
case 'x':
return XPreview;
case 'facebook':
return FacebookPreview;
case 'instagram':
case 'instagram-facebook':
return InstagramPreview;
case 'threads':
return ThreadsPreview;
case 'tiktok':
return TikTokPreview;
case 'youtube':
return YouTubePreview;
case 'pinterest':
return PinterestPreview;
case 'bluesky':
return BlueskyPreview;
case 'mastodon':
return MastodonPreview;
case 'telegram':
return TelegramPreview;
case 'discord':
return DiscordPreview;
default:
return LinkedInPreview;
}
});
</script>
<template>
<component
:is="previewComponent"
:social-account="resolvedSocialAccount"
:content="content"
:media="media"
:content-type="contentType"
:meta="meta"
:posted-at="postedAt"
/>
</template>