Added world edit subscription
And also toast lifetimes
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { PhCircleNotch } from "@phosphor-icons/vue";
|
import { PhCircleNotch } from "@phosphor-icons/vue";
|
||||||
import { useToast } from "~/components/ui/toast";
|
import { useToast } from "~/components/ui/toast";
|
||||||
|
import { ToastLifetime } from "~/components/ui/toast/use-toast";
|
||||||
import type { Calendar } from "~/models/CalendarConfig";
|
import type { Calendar } from "~/models/CalendarConfig";
|
||||||
|
|
||||||
const { toast } = useToast()
|
const { toast } = useToast()
|
||||||
@@ -28,7 +29,7 @@ async function handleAction(): Promise<void> {
|
|||||||
toast({
|
toast({
|
||||||
title: t("entity.calendar.deletedToast.title", { calendar: props.calendar.name }),
|
title: t("entity.calendar.deletedToast.title", { calendar: props.calendar.name }),
|
||||||
variant: "success",
|
variant: "success",
|
||||||
duration: 3000
|
duration: ToastLifetime.SHORT
|
||||||
})
|
})
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err)
|
console.log(err)
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { PhCircleNotch } from "@phosphor-icons/vue";
|
import { PhCircleNotch } from "@phosphor-icons/vue";
|
||||||
import { useToast } from "~/components/ui/toast";
|
import { useToast } from "~/components/ui/toast";
|
||||||
|
import { ToastLifetime } from "~/components/ui/toast/use-toast";
|
||||||
|
|
||||||
const { resetSkeleton, deleteEventFromSkeleton, cancelLatestRequest } = useCalendar()
|
const { resetSkeleton, deleteEventFromSkeleton, cancelLatestRequest } = useCalendar()
|
||||||
const { isDeleteEventModalOpen, eventSkeleton } = storeToRefs(useCalendar())
|
const { isDeleteEventModalOpen, eventSkeleton } = storeToRefs(useCalendar())
|
||||||
@@ -30,7 +31,7 @@ async function handleAction(): Promise<void> {
|
|||||||
toast({
|
toast({
|
||||||
title: t("entity.calendar.event.deletedToast.title", { event: eventTitle }),
|
title: t("entity.calendar.event.deletedToast.title", { event: eventTitle }),
|
||||||
variant: "success",
|
variant: "success",
|
||||||
duration: 3000
|
duration: ToastLifetime.MEDIUM
|
||||||
})
|
})
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err instanceof Error) {
|
if (err instanceof Error) {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { PhAlarm, PhCircleNotch, PhEye, PhEyeClosed, PhMapPinArea, PhPencilSimpleLine, PhTag } from "@phosphor-icons/vue"
|
import { PhAlarm, PhCircleNotch, PhEye, PhEyeClosed, PhMapPinArea, PhPencilSimpleLine, PhTag } from "@phosphor-icons/vue"
|
||||||
import { useToast } from "~/components/ui/toast";
|
import { useToast } from "~/components/ui/toast";
|
||||||
|
import { ToastLifetime } from "~/components/ui/toast/use-toast";
|
||||||
import type { APIError } from "~/models/Errors";
|
import type { APIError } from "~/models/Errors";
|
||||||
|
|
||||||
const emit = defineEmits(["event-updated"])
|
const emit = defineEmits(["event-updated"])
|
||||||
@@ -30,7 +31,7 @@ async function handleAction() {
|
|||||||
toast({
|
toast({
|
||||||
title: t("entity.calendar.event.updatedToast.title", { event: eventSkeleton.value.title }),
|
title: t("entity.calendar.event.updatedToast.title", { event: eventSkeleton.value.title }),
|
||||||
variant: "success",
|
variant: "success",
|
||||||
duration: 3000
|
duration: ToastLifetime.SHORT
|
||||||
})
|
})
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
@@ -41,7 +42,7 @@ async function handleAction() {
|
|||||||
title: t("entity.calendar.event.editErrors.toastTitle"),
|
title: t("entity.calendar.event.editErrors.toastTitle"),
|
||||||
variant: "destructive",
|
variant: "destructive",
|
||||||
description: t(`entity.calendar.event.editErrors.${error.path[1]}_${error.code}`),
|
description: t(`entity.calendar.event.editErrors.${error.path[1]}_${error.code}`),
|
||||||
duration: 2000,
|
duration: ToastLifetime.MEDIUM,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -5,6 +5,12 @@ import type { ToastProps } from "."
|
|||||||
const TOAST_LIMIT = 3
|
const TOAST_LIMIT = 3
|
||||||
const TOAST_REMOVE_DELAY = 1000000
|
const TOAST_REMOVE_DELAY = 1000000
|
||||||
|
|
||||||
|
export enum ToastLifetime {
|
||||||
|
SHORT = 2000,
|
||||||
|
MEDIUM = 3500,
|
||||||
|
LONG = 6000,
|
||||||
|
}
|
||||||
|
|
||||||
export type StringOrVNode =
|
export type StringOrVNode =
|
||||||
| string
|
| string
|
||||||
| VNode
|
| VNode
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { PhCircleNotch } from "@phosphor-icons/vue";
|
import { PhCircleNotch } from "@phosphor-icons/vue";
|
||||||
import { useToast } from "~/components/ui/toast";
|
import { useToast } from "~/components/ui/toast";
|
||||||
|
import { ToastLifetime } from "~/components/ui/toast/use-toast";
|
||||||
import type { World } from "~/models/World";
|
import type { World } from "~/models/World";
|
||||||
|
|
||||||
const { toast } = useToast()
|
const { toast } = useToast()
|
||||||
@@ -28,7 +29,7 @@ async function handleAction(): Promise<void> {
|
|||||||
toast({
|
toast({
|
||||||
title: t("entity.world.deletedToast.title", { world: props.world.name }),
|
title: t("entity.world.deletedToast.title", { world: props.world.name }),
|
||||||
variant: "success",
|
variant: "success",
|
||||||
duration: 3000
|
duration: ToastLifetime.SHORT
|
||||||
})
|
})
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err)
|
console.log(err)
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { PhCircleNotch } from "@phosphor-icons/vue";
|
import { PhCircleNotch } from "@phosphor-icons/vue";
|
||||||
import { useToast } from "~/components/ui/toast";
|
import { useToast } from "~/components/ui/toast";
|
||||||
|
import { ToastLifetime } from "~/components/ui/toast/use-toast";
|
||||||
import type { World } from "~/models/World";
|
import type { World } from "~/models/World";
|
||||||
|
|
||||||
const { toast } = useToast()
|
const { toast } = useToast()
|
||||||
@@ -36,7 +37,7 @@ async function handleSubmit() {
|
|||||||
toast({
|
toast({
|
||||||
title: t("entity.world.updatedToast.title", { world: worldSkeleton.value.name }),
|
title: t("entity.world.updatedToast.title", { world: worldSkeleton.value.name }),
|
||||||
variant: "success",
|
variant: "success",
|
||||||
duration: 3000
|
duration: ToastLifetime.SHORT
|
||||||
})
|
})
|
||||||
|
|
||||||
emit("on-close")
|
emit("on-close")
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
import type { RealtimeChannel } from "@supabase/supabase-js"
|
import type { RealtimeChannel } from "@supabase/supabase-js"
|
||||||
import type { World } from "~/models/World";
|
import type { World } from "~/models/World";
|
||||||
import type { Calendar } from "~/models/CalendarConfig";
|
import type { Calendar } from "~/models/CalendarConfig";
|
||||||
import { PhArrowBendDoubleUpLeft, PhGlobeHemisphereWest, PhPlus, PhTrash } from "@phosphor-icons/vue";
|
import { PhArrowBendDoubleUpLeft, PhGlobeHemisphereWest, PhPencil, PhPlus, PhTrash } from "@phosphor-icons/vue";
|
||||||
|
|
||||||
const supabase = useSupabaseClient()
|
const supabase = useSupabaseClient()
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
@@ -30,11 +30,13 @@ function hideCreateDialog() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* === Calendar subscriptions ===
|
* === Subscriptions ===
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** Active calendar channel */
|
/** Active calendar channel */
|
||||||
let calendarChannel: RealtimeChannel
|
let calendarChannel: RealtimeChannel
|
||||||
|
/** Active world channel */
|
||||||
|
let worldChannel: RealtimeChannel
|
||||||
|
|
||||||
/** Handles calendar insertion realtime events */
|
/** Handles calendar insertion realtime events */
|
||||||
function handleInsertedCalendar(newCalendar: Calendar) {
|
function handleInsertedCalendar(newCalendar: Calendar) {
|
||||||
@@ -81,24 +83,59 @@ onMounted(() => {
|
|||||||
)
|
)
|
||||||
.subscribe()
|
.subscribe()
|
||||||
})
|
})
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
// Unsubscribe from realtime
|
// Unsubscribe from realtime
|
||||||
supabase.removeChannel(calendarChannel)
|
supabase.removeChannel(calendarChannel)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
worldChannel = supabase.channel("realtime-world-channel")
|
||||||
|
.on(
|
||||||
|
"postgres_changes",
|
||||||
|
{ event: "*", schema: "public", table: "worlds" },
|
||||||
|
async (payload) => {
|
||||||
|
switch (payload.eventType) {
|
||||||
|
case "UPDATE":
|
||||||
|
if (!world.value?.data) return
|
||||||
|
|
||||||
|
world.value.data = (await $fetch<{ data: World }>("/api/worlds/query", { query: { id, full: true } })).data
|
||||||
|
break
|
||||||
|
|
||||||
|
default:
|
||||||
|
console.log("Unknown event has been triggered. This should not happen unless Supabase added one somehow.")
|
||||||
|
console.log(payload)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.subscribe()
|
||||||
|
})
|
||||||
|
onUnmounted(() => {
|
||||||
|
// Unsubscribe from realtime
|
||||||
|
supabase.removeChannel(worldChannel)
|
||||||
|
})
|
||||||
|
|
||||||
const markedCalendar = ref<Calendar | null>(null)
|
const markedCalendar = ref<Calendar | null>(null)
|
||||||
const isDeleteCalendarModalOpen = ref<boolean>(false)
|
const isDeleteCalendarModalOpen = ref<boolean>(false)
|
||||||
|
const isEditWorldModalOpen = ref<boolean>(false)
|
||||||
|
|
||||||
function deployDeleteModal(calendar: Calendar) {
|
function deployDeleteCalendarModal(calendar: Calendar) {
|
||||||
isDeleteCalendarModalOpen.value = true
|
isDeleteCalendarModalOpen.value = true
|
||||||
markedCalendar.value = calendar
|
markedCalendar.value = calendar
|
||||||
}
|
}
|
||||||
|
|
||||||
function hideDeleteModal() {
|
function hideDeleteCalendarModal() {
|
||||||
isDeleteCalendarModalOpen.value = false
|
isDeleteCalendarModalOpen.value = false
|
||||||
markedCalendar.value = null
|
markedCalendar.value = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function deployEditModal() {
|
||||||
|
isEditWorldModalOpen.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideEditModal() {
|
||||||
|
isEditWorldModalOpen.value = false
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -119,7 +156,24 @@ function hideDeleteModal() {
|
|||||||
|
|
||||||
<header class="lg:w-1/2 mb-8">
|
<header class="lg:w-1/2 mb-8">
|
||||||
<Spacing>
|
<Spacing>
|
||||||
<Heading level="h1">{{ world.data.name }}</Heading>
|
<div class="flex items-center gap-2">
|
||||||
|
<Heading level="h1">{{ world.data.name }}</Heading>
|
||||||
|
|
||||||
|
<UiTooltipProvider :delay-duration="250">
|
||||||
|
<UiTooltip>
|
||||||
|
<UiTooltipTrigger as-child>
|
||||||
|
<UiButton size="icon" class="rounded-full h-8 w-8" @click="deployEditModal">
|
||||||
|
<PhPencil size="17" weight="fill" />
|
||||||
|
</UiButton>
|
||||||
|
</UiTooltipTrigger>
|
||||||
|
<UiTooltipContent :side-offset="10">
|
||||||
|
<p>
|
||||||
|
{{ $t('entity.calendar.addSingle') }}
|
||||||
|
</p>
|
||||||
|
</UiTooltipContent>
|
||||||
|
</UiTooltip>
|
||||||
|
</UiTooltipProvider>
|
||||||
|
</div>
|
||||||
|
|
||||||
<p>{{ world.data.description }}</p>
|
<p>{{ world.data.description }}</p>
|
||||||
</Spacing>
|
</Spacing>
|
||||||
@@ -161,7 +215,7 @@ function hideDeleteModal() {
|
|||||||
<UiCardContent>
|
<UiCardContent>
|
||||||
<p class="italic">Description future (ou alors des informations sur le nb d'évènements)</p>
|
<p class="italic">Description future (ou alors des informations sur le nb d'évènements)</p>
|
||||||
|
|
||||||
<UiButton size="icon" variant="ghost" class="absolute top-2 right-2 z-20 hover:text-white hover:bg-rose-400 dark:hover:bg-rose-700" @click="deployDeleteModal(calendar)">
|
<UiButton size="icon" variant="ghost" class="absolute top-2 right-2 z-20 hover:text-white hover:bg-rose-400 dark:hover:bg-rose-700" @click="deployDeleteCalendarModal(calendar)">
|
||||||
<PhTrash size="16" />
|
<PhTrash size="16" />
|
||||||
</UiButton>
|
</UiButton>
|
||||||
</UiCardContent>
|
</UiCardContent>
|
||||||
@@ -176,8 +230,9 @@ function hideDeleteModal() {
|
|||||||
</Spacing>
|
</Spacing>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
<WorldDialogEdit :world="world.data" :modal-state="isEditWorldModalOpen" @on-close="hideEditModal" />
|
||||||
<CalendarDialogCreate :world="world.data" :modal-state="isCreateCalendarModalOpen" @on-close="hideCreateDialog" />
|
<CalendarDialogCreate :world="world.data" :modal-state="isCreateCalendarModalOpen" @on-close="hideCreateDialog" />
|
||||||
<CalendarDialogDelete :calendar="markedCalendar" :modal-state="isDeleteCalendarModalOpen" @on-close="hideDeleteModal" />
|
<CalendarDialogDelete :calendar="markedCalendar" :modal-state="isDeleteCalendarModalOpen" @on-close="hideDeleteCalendarModal" />
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<div class="h-full w-full grid place-items-center">
|
<div class="h-full w-full grid place-items-center">
|
||||||
|
|||||||
Reference in New Issue
Block a user