feat: adding tests
This commit is contained in:
parent
fb732495b2
commit
9ffb3bb98e
45 changed files with 385 additions and 120 deletions
|
|
@ -1,3 +1,4 @@
|
|||
/* eslint-disable @typescript-eslint/no-require-imports */
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
presets: [
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
import '../css/app.css';
|
||||
|
||||
import { createInertiaApp } from '@inertiajs/vue3';
|
||||
import { configureEcho } from '@laravel/echo-vue';
|
||||
import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers';
|
||||
import { i18nVue } from 'laravel-vue-i18n';
|
||||
import type { DefineComponent } from 'vue';
|
||||
import { createApp, h } from 'vue';
|
||||
import { i18nVue } from 'laravel-vue-i18n';
|
||||
|
||||
import { initializeTheme } from './composables/useAppearance';
|
||||
import { configureEcho } from '@laravel/echo-vue';
|
||||
|
||||
configureEcho({
|
||||
broadcaster: 'reverb',
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import { Calendar, Menu, Settings, Share2, Users } from 'lucide-vue-next';
|
|||
import { computed } from 'vue';
|
||||
|
||||
import Breadcrumbs from '@/components/Breadcrumbs.vue';
|
||||
import WorkspaceSwitcher from '@/components/WorkspaceSwitcher.vue';
|
||||
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
|
|
@ -27,9 +26,10 @@ import {
|
|||
SheetTrigger,
|
||||
} from '@/components/ui/sheet';
|
||||
import UserMenuContent from '@/components/UserMenuContent.vue';
|
||||
import WorkspaceSwitcher from '@/components/WorkspaceSwitcher.vue';
|
||||
import { useActiveUrl } from '@/composables/useActiveUrl';
|
||||
import { calendar } from '@/routes';
|
||||
import { getInitials } from '@/composables/useInitials';
|
||||
import { calendar } from '@/routes';
|
||||
import type { BreadcrumbItem, NavItem } from '@/types';
|
||||
|
||||
interface Props {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
<script setup lang="ts">
|
||||
import { router } from '@inertiajs/vue3';
|
||||
import { ref } from 'vue';
|
||||
|
||||
import {
|
||||
AlertDialog,
|
||||
AlertDialogAction,
|
||||
|
|
@ -9,8 +12,6 @@ import {
|
|||
AlertDialogHeader,
|
||||
AlertDialogTitle,
|
||||
} from '@/components/ui/alert-dialog';
|
||||
import { router } from '@inertiajs/vue3';
|
||||
import { ref } from 'vue';
|
||||
|
||||
const props = defineProps({
|
||||
title: {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,8 @@
|
|||
<script setup lang="ts">
|
||||
import { parseDate } from '@internationalized/date';
|
||||
import { IconCalendar } from '@tabler/icons-vue';
|
||||
import { ref, watch } from 'vue';
|
||||
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Calendar } from '@/components/ui/calendar';
|
||||
import { InputMask } from '@/components/ui/input';
|
||||
|
|
@ -9,9 +13,6 @@ import {
|
|||
} from '@/components/ui/popover';
|
||||
import { useDateMaska } from '@/composables/useDateMaska';
|
||||
import dayjs from '@/dayjs';
|
||||
import { parseDate } from '@internationalized/date';
|
||||
import { IconCalendar } from '@tabler/icons-vue';
|
||||
import { ref, watch } from 'vue';
|
||||
|
||||
const props = defineProps({
|
||||
name: {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,8 @@
|
|||
<script setup lang="ts">
|
||||
import { IconCheck, IconChevronDown, IconSearch } from '@tabler/icons-vue';
|
||||
import { FocusScope } from 'reka-ui';
|
||||
import { ref, watchEffect } from 'vue';
|
||||
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
Combobox,
|
||||
|
|
@ -11,9 +15,6 @@ import {
|
|||
ComboboxList,
|
||||
ComboboxTrigger,
|
||||
} from '@/components/ui/combobox';
|
||||
import { IconCheck, IconChevronDown, IconSearch } from '@tabler/icons-vue';
|
||||
import { FocusScope } from 'reka-ui';
|
||||
import { ref, watchEffect } from 'vue';
|
||||
|
||||
interface Language {
|
||||
id: string;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,9 @@
|
|||
<script setup lang="ts">
|
||||
import { router } from '@inertiajs/vue3';
|
||||
import axios from 'axios';
|
||||
import { Trash2, Upload, User } from 'lucide-vue-next';
|
||||
import { ref, watch } from 'vue';
|
||||
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
Dialog,
|
||||
|
|
@ -13,10 +18,6 @@ import {
|
|||
TooltipTrigger,
|
||||
} from '@/components/ui/tooltip';
|
||||
import { store as storeMedia, destroy as destroyMedia } from '@/routes/medias';
|
||||
import { router } from '@inertiajs/vue3';
|
||||
import axios from 'axios';
|
||||
import { Trash2, Upload, User } from 'lucide-vue-next';
|
||||
import { ref, watch } from 'vue';
|
||||
|
||||
interface Photo {
|
||||
url: string;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<script setup lang="ts">
|
||||
import { router } from '@inertiajs/vue3';
|
||||
import { computed, onMounted, onUnmounted } from 'vue';
|
||||
import { AlertCircle, Check, ExternalLink, RefreshCw, Trash2 } from 'lucide-vue-next';
|
||||
import { computed, onMounted, onUnmounted } from 'vue';
|
||||
|
||||
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
|
||||
import { Button } from '@/components/ui/button';
|
||||
|
|
|
|||
|
|
@ -1,4 +1,8 @@
|
|||
<script setup lang="ts">
|
||||
import { IconCheck, IconChevronDown, IconSearch } from '@tabler/icons-vue';
|
||||
import { FocusScope } from 'reka-ui';
|
||||
import { ref, watchEffect } from 'vue';
|
||||
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
Combobox,
|
||||
|
|
@ -11,9 +15,6 @@ import {
|
|||
ComboboxList,
|
||||
ComboboxTrigger,
|
||||
} from '@/components/ui/combobox';
|
||||
import { IconCheck, IconChevronDown, IconSearch } from '@tabler/icons-vue';
|
||||
import { FocusScope } from 'reka-ui';
|
||||
import { ref, watchEffect } from 'vue';
|
||||
|
||||
interface Timezone {
|
||||
value: string;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
<script setup lang="ts">
|
||||
import { usePage } from '@inertiajs/vue3';
|
||||
import { computed, ref, watch } from 'vue';
|
||||
|
||||
import {
|
||||
IconAlertTriangle,
|
||||
IconCircleCheck,
|
||||
|
|
@ -9,6 +7,8 @@ import {
|
|||
IconInfoCircle,
|
||||
IconX,
|
||||
} from '@tabler/icons-vue';
|
||||
import { computed, ref, watch } from 'vue';
|
||||
|
||||
|
||||
const show = ref(false);
|
||||
const animate = ref(false);
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ interface Props {
|
|||
isUploading?: boolean;
|
||||
}
|
||||
|
||||
const props = defineProps<Props>();
|
||||
defineProps<Props>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:content': [value: string];
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
<script setup lang="ts">
|
||||
import {
|
||||
IconDots,
|
||||
IconVideo,
|
||||
IconX,
|
||||
IconPhoto,
|
||||
IconThumbUp,
|
||||
|
|
@ -36,7 +35,7 @@ interface Props {
|
|||
isUploading?: boolean;
|
||||
}
|
||||
|
||||
const props = defineProps<Props>();
|
||||
defineProps<Props>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:content': [value: string];
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import {
|
||||
IconDots,
|
||||
IconVideo,
|
||||
|
|
@ -11,6 +10,8 @@ import {
|
|||
IconBookmark,
|
||||
IconMusic,
|
||||
} from '@tabler/icons-vue';
|
||||
import { computed } from 'vue';
|
||||
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
|
|
@ -58,7 +59,6 @@ const props = defineProps<Props>();
|
|||
// Computed helpers for content type
|
||||
const isReel = computed(() => props.contentType === 'instagram_reel');
|
||||
const isStory = computed(() => props.contentType === 'instagram_story');
|
||||
const isFeed = computed(() => props.contentType === 'instagram_feed' || !props.contentType);
|
||||
const hasMultipleContentTypes = computed(() => (props.contentTypeOptions?.length || 0) > 1);
|
||||
|
||||
const emit = defineEmits<{
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import {
|
||||
IconWorld,
|
||||
IconThumbUp,
|
||||
|
|
@ -7,7 +6,6 @@ import {
|
|||
IconRepeat,
|
||||
IconSend,
|
||||
IconDots,
|
||||
IconVideo,
|
||||
IconX,
|
||||
IconPhoto,
|
||||
IconHeart,
|
||||
|
|
@ -39,7 +37,7 @@ interface Props {
|
|||
isUploading?: boolean;
|
||||
}
|
||||
|
||||
const props = defineProps<Props>();
|
||||
defineProps<Props>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:content': [value: string];
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ interface Props {
|
|||
isUploading?: boolean;
|
||||
}
|
||||
|
||||
const props = defineProps<Props>();
|
||||
defineProps<Props>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:content': [value: string];
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import {
|
||||
IconX,
|
||||
IconPhoto,
|
||||
IconShare,
|
||||
IconUpload,
|
||||
} from '@tabler/icons-vue';
|
||||
import { computed } from 'vue';
|
||||
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
|
|
@ -173,7 +174,7 @@ const updateBoardId = (boardId: string) => {
|
|||
<div v-else class="relative">
|
||||
<div class="flex overflow-x-auto snap-x snap-mandatory scrollbar-hide">
|
||||
<div
|
||||
v-for="(item, index) in media"
|
||||
v-for="item in media"
|
||||
:key="item.id"
|
||||
class="relative flex-shrink-0 w-full snap-center"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -1,15 +1,16 @@
|
|||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import LinkedInPreview from './LinkedInPreview.vue';
|
||||
import XPreview from './XPreview.vue';
|
||||
|
||||
import BlueskyPreview from './BlueskyPreview.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 ThreadsPreview from './ThreadsPreview.vue';
|
||||
import TikTokPreview from './TikTokPreview.vue';
|
||||
import XPreview from './XPreview.vue';
|
||||
import YouTubePreview from './YouTubePreview.vue';
|
||||
import PinterestPreview from './PinterestPreview.vue';
|
||||
import BlueskyPreview from './BlueskyPreview.vue';
|
||||
import MastodonPreview from './MastodonPreview.vue';
|
||||
|
||||
interface SocialAccount {
|
||||
id: string;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
<script setup lang="ts">
|
||||
import {
|
||||
IconDots,
|
||||
IconVideo,
|
||||
IconX,
|
||||
IconPhoto,
|
||||
IconHeart,
|
||||
|
|
@ -36,7 +35,7 @@ interface Props {
|
|||
isUploading?: boolean;
|
||||
}
|
||||
|
||||
const props = defineProps<Props>();
|
||||
defineProps<Props>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:content': [value: string];
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ interface Props {
|
|||
isUploading?: boolean;
|
||||
}
|
||||
|
||||
const props = defineProps<Props>();
|
||||
defineProps<Props>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:content': [value: string];
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
<script setup lang="ts">
|
||||
import {
|
||||
IconDots,
|
||||
IconVideo,
|
||||
IconX,
|
||||
IconPhoto,
|
||||
IconHeart,
|
||||
|
|
@ -38,7 +37,7 @@ interface Props {
|
|||
isUploading?: boolean;
|
||||
}
|
||||
|
||||
const props = defineProps<Props>();
|
||||
defineProps<Props>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:content': [value: string];
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ interface Props {
|
|||
isUploading?: boolean;
|
||||
}
|
||||
|
||||
const props = defineProps<Props>();
|
||||
defineProps<Props>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:content': [value: string];
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ export default {
|
|||
|
||||
formatDuration(duration: string) {
|
||||
// Duration comes in format "HH:mm:ss"
|
||||
const [hours, minutes, seconds] = duration.split(':');
|
||||
const [hours, minutes] = duration.split(':');
|
||||
const h = parseInt(hours, 10);
|
||||
const m = parseInt(minutes, 10);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<script setup lang="ts">
|
||||
import { Link } from '@inertiajs/vue3';
|
||||
|
||||
import { home } from '@/routes';
|
||||
|
||||
defineProps<{
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<script setup lang="ts">
|
||||
import { Link } from '@inertiajs/vue3';
|
||||
|
||||
import { home } from '@/routes';
|
||||
|
||||
defineProps<{
|
||||
|
|
|
|||
|
|
@ -1,19 +1,19 @@
|
|||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { IconInfoCircle } from '@tabler/icons-vue';
|
||||
import { ref } from 'vue';
|
||||
|
||||
import PopupLayout from '@/layouts/PopupLayout.vue';
|
||||
import { Alert, AlertDescription } from '@/components/ui/alert';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Alert, AlertDescription } from '@/components/ui/alert';
|
||||
import PopupLayout from '@/layouts/PopupLayout.vue';
|
||||
import { store as storeBluesky } from '@/routes/social/bluesky';
|
||||
|
||||
interface Props {
|
||||
errors?: Record<string, string>;
|
||||
}
|
||||
|
||||
const props = defineProps<Props>();
|
||||
defineProps<Props>();
|
||||
|
||||
const formRef = ref<HTMLFormElement | null>(null);
|
||||
const identifier = ref('');
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { Facebook, Check } from 'lucide-vue-next';
|
||||
import { ref } from 'vue';
|
||||
|
||||
import PopupLayout from '@/layouts/PopupLayout.vue';
|
||||
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
|
||||
import { Alert, AlertDescription } from '@/components/ui/alert';
|
||||
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
|
||||
import PopupLayout from '@/layouts/PopupLayout.vue';
|
||||
import { select as selectFacebookPage } from '@/routes/social/facebook';
|
||||
|
||||
interface Page {
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@
|
|||
import { Head } from '@inertiajs/vue3';
|
||||
import { ref } from 'vue';
|
||||
|
||||
import AppLayout from '@/layouts/AppLayout.vue';
|
||||
import ConfirmDeleteModal from '@/components/ConfirmDeleteModal.vue';
|
||||
import SocialAccountsGrid, { type Platform } from '@/components/SocialAccountsGrid.vue';
|
||||
import AppLayout from '@/layouts/AppLayout.vue';
|
||||
import { accounts } from '@/routes';
|
||||
import { disconnect as disconnectAccount } from '@/routes/accounts';
|
||||
import { type BreadcrumbItemType } from '@/types';
|
||||
|
|
@ -19,7 +19,7 @@ interface Props {
|
|||
platforms: Platform[];
|
||||
}
|
||||
|
||||
const props = defineProps<Props>();
|
||||
defineProps<Props>();
|
||||
|
||||
const deleteModal = ref<InstanceType<typeof ConfirmDeleteModal> | null>(null);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { Building2, Check } from 'lucide-vue-next';
|
||||
import { ref } from 'vue';
|
||||
|
||||
import PopupLayout from '@/layouts/PopupLayout.vue';
|
||||
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
|
||||
import { Alert, AlertDescription } from '@/components/ui/alert';
|
||||
import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
|
||||
import PopupLayout from '@/layouts/PopupLayout.vue';
|
||||
import { select as selectLinkedInPage } from '@/routes/social/linkedin-page';
|
||||
|
||||
interface Organization {
|
||||
|
|
|
|||
|
|
@ -1,19 +1,19 @@
|
|||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { IconInfoCircle } from '@tabler/icons-vue';
|
||||
import { ref } from 'vue';
|
||||
|
||||
import PopupLayout from '@/layouts/PopupLayout.vue';
|
||||
import { Alert, AlertDescription } from '@/components/ui/alert';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Alert, AlertDescription } from '@/components/ui/alert';
|
||||
import PopupLayout from '@/layouts/PopupLayout.vue';
|
||||
import { authorize as authorizeMastodon } from '@/routes/social/mastodon';
|
||||
|
||||
interface Props {
|
||||
errors?: Record<string, string>;
|
||||
}
|
||||
|
||||
const props = defineProps<Props>();
|
||||
defineProps<Props>();
|
||||
|
||||
const formRef = ref<HTMLFormElement | null>(null);
|
||||
const instance = ref('https://mastodon.social');
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@
|
|||
import { Head } from '@inertiajs/vue3';
|
||||
import { CreditCard, FileText, Building2, ExternalLink, Sparkles } from 'lucide-vue-next';
|
||||
|
||||
import AppLayout from '@/layouts/AppLayout.vue';
|
||||
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert';
|
||||
import AppLayout from '@/layouts/AppLayout.vue';
|
||||
import { type BreadcrumbItemType } from '@/types';
|
||||
|
||||
interface Subscription {
|
||||
|
|
@ -40,7 +40,7 @@ interface Props {
|
|||
defaultPaymentMethod: PaymentMethod | null;
|
||||
}
|
||||
|
||||
const props = defineProps<Props>();
|
||||
defineProps<Props>();
|
||||
|
||||
const breadcrumbs: BreadcrumbItemType[] = [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
<script setup lang="ts">
|
||||
import { Head } from '@inertiajs/vue3';
|
||||
import { ref } from 'vue';
|
||||
import { Plus, Hash, Pencil, Trash2 } from 'lucide-vue-next';
|
||||
import { ref } from 'vue';
|
||||
|
||||
import AppLayout from '@/layouts/AppLayout.vue';
|
||||
import ConfirmDeleteModal from '@/components/ConfirmDeleteModal.vue';
|
||||
import CreateDialog from '@/components/hashtags/CreateDialog.vue';
|
||||
import EditDialog from '@/components/hashtags/EditDialog.vue';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import AppLayout from '@/layouts/AppLayout.vue';
|
||||
import { index as hashtagsIndex, destroy as hashtagsDestroy } from '@/routes/hashtags';
|
||||
import { type BreadcrumbItemType } from '@/types';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
<script setup lang="ts">
|
||||
import { Head, Link, router } from '@inertiajs/vue3';
|
||||
import { ref } from 'vue';
|
||||
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { Spinner } from '@/components/ui/spinner';
|
||||
import { login, register } from '@/routes';
|
||||
import { ref } from 'vue';
|
||||
|
||||
const props = defineProps<{
|
||||
invite: {
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
<script setup lang="ts">
|
||||
import { Head } from '@inertiajs/vue3';
|
||||
import { ref } from 'vue';
|
||||
import { Plus, Tag, Pencil, Trash2 } from 'lucide-vue-next';
|
||||
import { ref } from 'vue';
|
||||
|
||||
import AppLayout from '@/layouts/AppLayout.vue';
|
||||
import ConfirmDeleteModal from '@/components/ConfirmDeleteModal.vue';
|
||||
import CreateDialog from '@/components/labels/CreateDialog.vue';
|
||||
import EditDialog from '@/components/labels/EditDialog.vue';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import AppLayout from '@/layouts/AppLayout.vue';
|
||||
import { index as labelsIndex, destroy as labelsDestroy } from '@/routes/labels';
|
||||
import { type BreadcrumbItemType } from '@/types';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
<script setup lang="ts">
|
||||
import { Head, useForm } from '@inertiajs/vue3';
|
||||
import { Building, Building2, Rocket, Sparkles, Store, User } from 'lucide-vue-next';
|
||||
import { computed } from 'vue';
|
||||
|
||||
import OnboardingLayout from '@/layouts/OnboardingLayout.vue';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { storeStep1 } from '@/actions/App/Http/Controllers/OnboardingController';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import OnboardingLayout from '@/layouts/OnboardingLayout.vue';
|
||||
|
||||
interface Persona {
|
||||
value: string;
|
||||
|
|
@ -18,7 +17,7 @@ interface Props {
|
|||
personas: Persona[];
|
||||
}
|
||||
|
||||
const props = defineProps<Props>();
|
||||
defineProps<Props>();
|
||||
|
||||
const form = useForm({
|
||||
persona: '',
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@
|
|||
import { Head, router } from '@inertiajs/vue3';
|
||||
import { ref, computed } from 'vue';
|
||||
|
||||
import OnboardingLayout from '@/layouts/OnboardingLayout.vue';
|
||||
import { storeStep2 } from '@/actions/App/Http/Controllers/OnboardingController';
|
||||
import SocialAccountsGrid, { type Platform } from '@/components/SocialAccountsGrid.vue';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { storeStep2 } from '@/actions/App/Http/Controllers/OnboardingController';
|
||||
import OnboardingLayout from '@/layouts/OnboardingLayout.vue';
|
||||
|
||||
interface Props {
|
||||
platforms: Platform[];
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
<script setup lang="ts">
|
||||
import { Head, Link, router } from '@inertiajs/vue3';
|
||||
import { computed } from 'vue';
|
||||
import { ChevronLeft, ChevronRight, Plus } from 'lucide-vue-next';
|
||||
import dayjs from '@/dayjs';
|
||||
import { computed } from 'vue';
|
||||
|
||||
import AppLayout from '@/layouts/AppLayout.vue';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||
import dayjs from '@/dayjs';
|
||||
import AppLayout from '@/layouts/AppLayout.vue';
|
||||
import { calendar } from '@/routes';
|
||||
import { create as createPost, edit as editPost, show as showPost } from '@/routes/posts';
|
||||
import { type BreadcrumbItemType } from '@/types';
|
||||
|
|
|
|||
|
|
@ -1,16 +1,13 @@
|
|||
<script setup lang="ts">
|
||||
import { Head, router } from '@inertiajs/vue3';
|
||||
import { computed, ref, watch } from 'vue';
|
||||
import { Clock, AlertCircle, Trash2, Send, Link2, MoreHorizontal, Plus } from 'lucide-vue-next';
|
||||
import axios from 'axios';
|
||||
import dayjs from '@/dayjs';
|
||||
import { PlatformPreview } from '@/components/posts/previews';
|
||||
import { Clock, AlertCircle, Trash2, Send, Link2, MoreHorizontal, Plus } from 'lucide-vue-next';
|
||||
import { computed, ref, watch } from 'vue';
|
||||
|
||||
import AppLayout from '@/layouts/AppLayout.vue';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Switch } from '@/components/ui/switch';
|
||||
import { store as storeMedia, storeChunked as storeMediaChunked, destroy as destroyMedia, duplicate as duplicateMedia } from '@/actions/App/Http/Controllers/MediaController';
|
||||
import ConfirmDeleteModal from '@/components/ConfirmDeleteModal.vue';
|
||||
import DatePicker from '@/components/DatePicker.vue';
|
||||
import { PlatformPreview } from '@/components/posts/previews';
|
||||
import { Alert, AlertDescription } from '@/components/ui/alert';
|
||||
import {
|
||||
AlertDialog,
|
||||
|
|
@ -22,6 +19,7 @@ import {
|
|||
AlertDialogHeader,
|
||||
AlertDialogTitle,
|
||||
} from '@/components/ui/alert-dialog';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
|
|
@ -29,22 +27,17 @@ import {
|
|||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from '@/components/ui/dialog';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Switch } from '@/components/ui/switch';
|
||||
import { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@/components/ui/select';
|
||||
import DatePicker from '@/components/DatePicker.vue';
|
||||
import ConfirmDeleteModal from '@/components/ConfirmDeleteModal.vue';
|
||||
import dayjs from '@/dayjs';
|
||||
import AppLayout from '@/layouts/AppLayout.vue';
|
||||
import { calendar } from '@/routes';
|
||||
import { destroy as destroyPost, update as updatePost } from '@/routes/posts';
|
||||
import { store as storeMedia, storeChunked as storeMediaChunked, destroy as destroyMedia, duplicate as duplicateMedia } from '@/actions/App/Http/Controllers/MediaController';
|
||||
import { uploadChunked, shouldUseChunkedUpload } from '@/utils/chunkedUpload';
|
||||
import { type BreadcrumbItemType } from '@/types';
|
||||
import { uploadChunked, shouldUseChunkedUpload } from '@/utils/chunkedUpload';
|
||||
|
||||
interface SocialAccount {
|
||||
id: string;
|
||||
|
|
@ -276,10 +269,6 @@ function getContentTypeOptions(platform: string): ContentTypeOption[] {
|
|||
return contentTypeOptions[platform] || [];
|
||||
}
|
||||
|
||||
function hasMultipleContentTypes(platform: string): boolean {
|
||||
return (contentTypeOptions[platform]?.length || 0) > 1;
|
||||
}
|
||||
|
||||
function getPlatformData(platform: string): Record<string, any> {
|
||||
if (platform === 'pinterest') {
|
||||
return { boards: props.pinterestBoards };
|
||||
|
|
@ -344,11 +333,6 @@ const selectedPlatforms = computed(() => {
|
|||
return props.post.post_platforms.filter(pp => selectedPlatformIds.value.includes(pp.id));
|
||||
});
|
||||
|
||||
// Unselected platforms (for add button)
|
||||
const unselectedPlatforms = computed(() => {
|
||||
return props.post.post_platforms.filter(pp => !selectedPlatformIds.value.includes(pp.id));
|
||||
});
|
||||
|
||||
// Other selected platforms (for sync label)
|
||||
const otherSelectedPlatforms = computed(() => {
|
||||
return selectedPlatforms.value.filter(pp => pp.id !== activeTabId.value);
|
||||
|
|
|
|||
274
resources/js/pages/posts/Index.vue
Normal file
274
resources/js/pages/posts/Index.vue
Normal file
|
|
@ -0,0 +1,274 @@
|
|||
<script setup lang="ts">
|
||||
import { Head, Link, router } from '@inertiajs/vue3';
|
||||
import { Clock, CheckCircle, AlertCircle, Loader2, FileText, Plus, Eye, Pencil, Trash2 } from 'lucide-vue-next';
|
||||
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card, CardContent } from '@/components/ui/card';
|
||||
import dayjs from '@/dayjs';
|
||||
import AppLayout from '@/layouts/AppLayout.vue';
|
||||
import { calendar } from '@/routes';
|
||||
import { index as postsIndex, create as createPost, show as showPost, edit as editPost, destroy as destroyPost } from '@/routes/posts';
|
||||
import { type BreadcrumbItemType } from '@/types';
|
||||
|
||||
interface SocialAccount {
|
||||
id: string;
|
||||
platform: string;
|
||||
display_name: string;
|
||||
username: string;
|
||||
avatar_url: string | null;
|
||||
}
|
||||
|
||||
interface PostPlatform {
|
||||
id: string;
|
||||
social_account_id: string;
|
||||
enabled: boolean;
|
||||
platform: string;
|
||||
content: string;
|
||||
status: string;
|
||||
social_account: SocialAccount;
|
||||
}
|
||||
|
||||
interface User {
|
||||
id: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
interface Post {
|
||||
id: string;
|
||||
status: string;
|
||||
scheduled_at: string | null;
|
||||
published_at: string | null;
|
||||
post_platforms: PostPlatform[];
|
||||
user: User;
|
||||
}
|
||||
|
||||
interface PaginatedPosts {
|
||||
data: Post[];
|
||||
links: {
|
||||
first: string | null;
|
||||
last: string | null;
|
||||
prev: string | null;
|
||||
next: string | null;
|
||||
};
|
||||
meta: {
|
||||
current_page: number;
|
||||
from: number | null;
|
||||
last_page: number;
|
||||
per_page: number;
|
||||
to: number | null;
|
||||
total: number;
|
||||
};
|
||||
}
|
||||
|
||||
interface Workspace {
|
||||
id: string;
|
||||
name: string;
|
||||
timezone: string;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
workspace: Workspace;
|
||||
posts: PaginatedPosts;
|
||||
}
|
||||
|
||||
const props = defineProps<Props>();
|
||||
|
||||
const breadcrumbs: BreadcrumbItemType[] = [
|
||||
{ title: 'Posts', href: postsIndex.url() },
|
||||
];
|
||||
|
||||
const getPlatformLogo = (platform: string): string => {
|
||||
const logos: Record<string, string> = {
|
||||
'linkedin': '/images/accounts/linkedin.png',
|
||||
'linkedin-page': '/images/accounts/linkedin.png',
|
||||
'x': '/images/accounts/x.png',
|
||||
'tiktok': '/images/accounts/tiktok.png',
|
||||
'youtube': '/images/accounts/youtube.png',
|
||||
'facebook': '/images/accounts/facebook.png',
|
||||
'instagram': '/images/accounts/instagram.png',
|
||||
'threads': '/images/accounts/threads.png',
|
||||
'pinterest': '/images/accounts/pinterest.png',
|
||||
'bluesky': '/images/accounts/bluesky.png',
|
||||
'mastodon': '/images/accounts/mastodon.png',
|
||||
};
|
||||
return logos[platform] || '/images/accounts/default.png';
|
||||
};
|
||||
|
||||
const getStatusConfig = (status: string) => {
|
||||
const configs: Record<string, { label: string; color: string; icon: typeof FileText }> = {
|
||||
'draft': { label: 'Rascunho', color: 'bg-gray-100 text-gray-800', icon: FileText },
|
||||
'scheduled': { label: 'Agendado', color: 'bg-blue-100 text-blue-800', icon: Clock },
|
||||
'publishing': { label: 'Publicando', color: 'bg-yellow-100 text-yellow-800', icon: Loader2 },
|
||||
'published': { label: 'Publicado', color: 'bg-green-100 text-green-800', icon: CheckCircle },
|
||||
'partially_published': { label: 'Parcialmente Publicado', color: 'bg-orange-100 text-orange-800', icon: AlertCircle },
|
||||
'failed': { label: 'Falhou', color: 'bg-red-100 text-red-800', icon: AlertCircle },
|
||||
};
|
||||
return configs[status] || configs['draft'];
|
||||
};
|
||||
|
||||
const formatDateTime = (date: string | null): string => {
|
||||
if (!date) return '-';
|
||||
return dayjs.utc(date).tz(props.workspace.timezone).format('D MMM YYYY, HH:mm');
|
||||
};
|
||||
|
||||
const getEnabledPlatforms = (post: Post) => {
|
||||
return post.post_platforms.filter(pp => pp.enabled);
|
||||
};
|
||||
|
||||
const getPostPreview = (post: Post): string => {
|
||||
const enabledPlatforms = getEnabledPlatforms(post);
|
||||
if (enabledPlatforms.length === 0) return 'Sem conteudo';
|
||||
const firstPlatform = enabledPlatforms[0];
|
||||
const content = firstPlatform.content || '';
|
||||
return content.length > 100 ? content.substring(0, 100) + '...' : content || 'Sem conteudo';
|
||||
};
|
||||
|
||||
const canEdit = (post: Post): boolean => {
|
||||
return ['draft', 'scheduled'].includes(post.status);
|
||||
};
|
||||
|
||||
const handleDelete = (post: Post) => {
|
||||
if (confirm('Tem certeza que deseja excluir este post?')) {
|
||||
router.delete(destroyPost.url(post.id));
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Head title="Posts" />
|
||||
|
||||
<AppLayout :breadcrumbs="breadcrumbs">
|
||||
<div class="flex flex-col gap-6 p-6">
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<h1 class="text-2xl font-bold tracking-tight">Posts</h1>
|
||||
<p class="text-muted-foreground">
|
||||
Gerencie todos os seus posts
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<Link :href="calendar.url()">
|
||||
<Button variant="outline">
|
||||
<Clock class="mr-2 h-4 w-4" />
|
||||
Calendario
|
||||
</Button>
|
||||
</Link>
|
||||
<Link :href="createPost.url()">
|
||||
<Button>
|
||||
<Plus class="mr-2 h-4 w-4" />
|
||||
Novo Post
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="posts.data.length === 0">
|
||||
<Card>
|
||||
<CardContent class="flex flex-col items-center justify-center py-12">
|
||||
<FileText class="h-12 w-12 text-muted-foreground" />
|
||||
<h3 class="mt-4 text-lg font-semibold">Nenhum post ainda</h3>
|
||||
<p class="mt-2 text-sm text-muted-foreground">
|
||||
Comece criando seu primeiro post.
|
||||
</p>
|
||||
<Link :href="createPost.url()" class="mt-4">
|
||||
<Button>
|
||||
<Plus class="mr-2 h-4 w-4" />
|
||||
Criar Post
|
||||
</Button>
|
||||
</Link>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
<div v-else class="space-y-4">
|
||||
<Card v-for="post in posts.data" :key="post.id">
|
||||
<CardContent class="p-4">
|
||||
<div class="flex items-start justify-between gap-4">
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-center gap-2 mb-2">
|
||||
<Badge :class="getStatusConfig(post.status).color">
|
||||
<component :is="getStatusConfig(post.status).icon" class="mr-1 h-3 w-3" />
|
||||
{{ getStatusConfig(post.status).label }}
|
||||
</Badge>
|
||||
<span class="text-sm text-muted-foreground">
|
||||
{{ formatDateTime(post.scheduled_at) }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<p class="text-sm text-foreground line-clamp-2 mb-3">
|
||||
{{ getPostPreview(post) }}
|
||||
</p>
|
||||
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="flex -space-x-2">
|
||||
<img
|
||||
v-for="pp in getEnabledPlatforms(post).slice(0, 5)"
|
||||
:key="pp.id"
|
||||
:src="getPlatformLogo(pp.platform)"
|
||||
:alt="pp.platform"
|
||||
class="h-6 w-6 rounded-full ring-2 ring-background"
|
||||
/>
|
||||
</div>
|
||||
<span v-if="getEnabledPlatforms(post).length > 5" class="text-xs text-muted-foreground">
|
||||
+{{ getEnabledPlatforms(post).length - 5 }}
|
||||
</span>
|
||||
<span class="text-xs text-muted-foreground ml-2">
|
||||
por {{ post.user.name }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-1">
|
||||
<Link :href="showPost.url(post.id)">
|
||||
<Button variant="ghost" size="icon">
|
||||
<Eye class="h-4 w-4" />
|
||||
</Button>
|
||||
</Link>
|
||||
<Link v-if="canEdit(post)" :href="editPost.url(post.id)">
|
||||
<Button variant="ghost" size="icon">
|
||||
<Pencil class="h-4 w-4" />
|
||||
</Button>
|
||||
</Link>
|
||||
<Button
|
||||
v-if="canEdit(post)"
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
@click="handleDelete(post)"
|
||||
>
|
||||
<Trash2 class="h-4 w-4 text-red-500" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<div v-if="posts.meta.last_page > 1" class="flex items-center justify-between">
|
||||
<p class="text-sm text-muted-foreground">
|
||||
Mostrando {{ posts.meta.from }} a {{ posts.meta.to }} de {{ posts.meta.total }} posts
|
||||
</p>
|
||||
<div class="flex gap-2">
|
||||
<Link
|
||||
v-if="posts.links.prev"
|
||||
:href="posts.links.prev"
|
||||
preserve-scroll
|
||||
>
|
||||
<Button variant="outline" size="sm">
|
||||
Anterior
|
||||
</Button>
|
||||
</Link>
|
||||
<Link
|
||||
v-if="posts.links.next"
|
||||
:href="posts.links.next"
|
||||
preserve-scroll
|
||||
>
|
||||
<Button variant="outline" size="sm">
|
||||
Proximo
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</AppLayout>
|
||||
</template>
|
||||
|
|
@ -3,12 +3,12 @@ import { Head, Link } from '@inertiajs/vue3';
|
|||
import { useEcho } from '@laravel/echo-vue';
|
||||
import { Clock, CheckCircle, AlertCircle, Loader2, FileText, ExternalLink, Pencil } from 'lucide-vue-next';
|
||||
import { ref, computed } from 'vue';
|
||||
import dayjs from '@/dayjs';
|
||||
|
||||
import AppLayout from '@/layouts/AppLayout.vue';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import dayjs from '@/dayjs';
|
||||
import AppLayout from '@/layouts/AppLayout.vue';
|
||||
import { calendar } from '@/routes';
|
||||
import { edit as editPost } from '@/routes/posts';
|
||||
import { type BreadcrumbItemType } from '@/types';
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import { Label } from '@/components/ui/label';
|
|||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||
import AppLayout from '@/layouts/AppLayout.vue';
|
||||
import SettingsLayout from '@/layouts/settings/Layout.vue';
|
||||
import { members } from '@/routes';
|
||||
import { members as membersRoute } from '@/routes';
|
||||
import { destroy as destroyInvite, store as storeInvite } from '@/routes/invites';
|
||||
import { remove as removeMember } from '@/routes/members';
|
||||
import { type BreadcrumbItem } from '@/types';
|
||||
|
|
@ -49,10 +49,10 @@ interface Props {
|
|||
roles: Role[];
|
||||
}
|
||||
|
||||
const props = defineProps<Props>();
|
||||
defineProps<Props>();
|
||||
|
||||
const breadcrumbItems: BreadcrumbItem[] = [
|
||||
{ title: 'Members', href: members.url() },
|
||||
{ title: 'Members', href: membersRoute.url() },
|
||||
];
|
||||
|
||||
const form = useForm({
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<script setup lang="ts">
|
||||
import { Form, Head, Link, usePage } from '@inertiajs/vue3';
|
||||
import { ref } from 'vue';
|
||||
|
||||
import ProfileController from '@/actions/App/Http/Controllers/Settings/ProfileController';
|
||||
import DeleteUser from '@/components/DeleteUser.vue';
|
||||
|
|
@ -15,7 +16,6 @@ import SettingsLayout from '@/layouts/settings/Layout.vue';
|
|||
import { edit } from '@/routes/profile';
|
||||
import { send } from '@/routes/verification';
|
||||
import { type BreadcrumbItem } from '@/types';
|
||||
import { ref } from 'vue';
|
||||
|
||||
interface Language {
|
||||
id: string;
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
<script setup lang="ts">
|
||||
import { Head, useForm } from '@inertiajs/vue3';
|
||||
|
||||
import AppLayout from '@/layouts/AppLayout.vue';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import AppLayout from '@/layouts/AppLayout.vue';
|
||||
import { type BreadcrumbItemType } from '@/types';
|
||||
|
||||
const breadcrumbs: BreadcrumbItemType[] = [
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@
|
|||
import { Head, Link, router } from '@inertiajs/vue3';
|
||||
import { Plus, Calendar, Users, Settings } from 'lucide-vue-next';
|
||||
|
||||
import AppLayout from '@/layouts/AppLayout.vue';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import AppLayout from '@/layouts/AppLayout.vue';
|
||||
import { accounts, calendar } from '@/routes';
|
||||
import { settings } from '@/routes/workspace';
|
||||
import { create as createWorkspace, index as workspacesIndex, switchMethod } from '@/routes/workspaces';
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@
|
|||
import { Head, Link } from '@inertiajs/vue3';
|
||||
import { Calendar, Users, FileText, CheckCircle, Clock, AlertCircle, Settings } from 'lucide-vue-next';
|
||||
|
||||
import AppLayout from '@/layouts/AppLayout.vue';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import AppLayout from '@/layouts/AppLayout.vue';
|
||||
import { accounts, calendar } from '@/routes';
|
||||
import { settings } from '@/routes/workspace';
|
||||
import { type BreadcrumbItemType } from '@/types';
|
||||
|
|
@ -35,7 +35,7 @@ interface Props {
|
|||
stats: Stats;
|
||||
}
|
||||
|
||||
const props = defineProps<Props>();
|
||||
defineProps<Props>();
|
||||
|
||||
const breadcrumbs: BreadcrumbItemType[] = [
|
||||
{ title: 'Calendar', href: calendar.url() },
|
||||
|
|
|
|||
|
|
@ -20,5 +20,7 @@ abstract class TestCase extends BaseTestCase
|
|||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->withoutVite();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue