feat: check validity of schedule time and show warning notice

shuuji3/feat/scheduled-post
TAKAHASHI Shuuji 2024-03-04 02:35:53 +09:00
rodzic dc2e49ffe4
commit dc4ba794f6
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: F15C887632129F5E
2 zmienionych plików z 32 dodań i 13 usunięć

Wyświetl plik

@ -131,14 +131,19 @@ const expiresInOptions = computed(() => [
const expiresInDefaultOptionIndex = 2 const expiresInDefaultOptionIndex = 2
const scheduledTime = ref('') const scheduledTime = ref('')
watchEffect(() => { const now = useNow({ interval: 1000 })
draft.value.params.scheduledAt = scheduledTime.value const minimumScheduledTime = computed(() => getMinimumScheduledTime(now.value))
const isValidScheduledTime = computed(() => {
if (scheduledTime.value === '')
return true
const scheduledTimeDate = new Date(scheduledTime.value)
return minimumScheduledTime.value.getTime() <= scheduledTimeDate.getTime()
}) })
const now = useNow({ interval: 1000 })
const minimumScheduledTime = ref()
watchEffect(() => { watchEffect(() => {
minimumScheduledTime.value = getMinimumScheduledTime(now.value) draft.value.params.scheduledAt = scheduledTime.value
}) })
// Calculate the minimum scheduled time. // Calculate the minimum scheduled time.
@ -146,13 +151,16 @@ watchEffect(() => {
// but if the specified scheduled time is less than 5 minutes, Mastodon will // but if the specified scheduled time is less than 5 minutes, Mastodon will
// send the post immediately. // send the post immediately.
// To prevent this, we add a buffer and round up the minutes. // To prevent this, we add a buffer and round up the minutes.
function getMinimumScheduledTime(now: Date): string { function getMinimumScheduledTime(now: Date): Date {
const bufferInSec = 5 + 5 * 60 // + 5 minutes and 5 seconds const bufferInSec = 5 + 5 * 60 // + 5 minutes and 5 seconds
const nowInSec = Math.floor(now.getTime() / 1000) const nowInSec = Math.floor(now.getTime() / 1000)
const bufferedTimeInSec const bufferedTimeInSec
= Math.ceil((nowInSec + bufferInSec) / 60) * 60 = Math.ceil((nowInSec + bufferInSec) / 60) * 60
const minimumScheduledTime = new Date(bufferedTimeInSec * 1000) return new Date(bufferedTimeInSec * 1000)
return minimumScheduledTime.toISOString().slice(0, 16) }
function getDatetimeInputFormat(time: Date) {
return time.toISOString().slice(0, 16)
} }
const characterCount = computed(() => { const characterCount = computed(() => {
@ -326,9 +334,9 @@ function stopQuestionMarkPropagation(e: KeyboardEvent) {
<div aria-hidden="true" i-ri:error-warning-fill /> <div aria-hidden="true" i-ri:error-warning-fill />
<p>{{ scheduledTime ? $t('state.schedule_failed') : $t('state.publish_failed') }}</p> <p>{{ scheduledTime ? $t('state.schedule_failed') : $t('state.publish_failed') }}</p>
</div> </div>
<CommonTooltip placement="bottom" :content="scheduledTime ? $t('state.clear_schedule_failed') : $t('action.clear_publish_failed')"> <CommonTooltip placement="bottom" :content="scheduledTime ? $t('action.clear_schedule_failed') : $t('action.clear_publish_failed')">
<button <button
flex rounded-4 p1 hover:bg-active cursor-pointer transition-100 :aria-label="scheduledTime ? $t('state.clear_schedule_failed') : $t('action.clear_publish_failed')" flex rounded-4 p1 hover:bg-active cursor-pointer transition-100 :aria-label="scheduledTime ? $t('action.clear_schedule_failed') : $t('action.clear_publish_failed')"
@click="failedMessages = []" @click="failedMessages = []"
> >
<span aria-hidden="true" w="1.75em" h="1.75em" i-ri:close-line /> <span aria-hidden="true" w="1.75em" h="1.75em" i-ri:close-line />
@ -343,6 +351,15 @@ function stopQuestionMarkPropagation(e: KeyboardEvent) {
</ol> </ol>
</CommonErrorMessage> </CommonErrorMessage>
<CommonErrorMessage v-if="!isValidScheduledTime" described-by="scheduled-time-invalid" pt-2>
<header id="scheduled-time-invalid" flex justify-between>
<div flex items-center gap-x-2 font-bold>
<div aria-hidden="true" i-ri:error-warning-fill />
<p>{{ $t('state.schedule_time_invalid', [minimumScheduledTime.toLocaleString()]) }}</p>
</div>
</header>
</CommonErrorMessage>
<div relative flex-1 flex flex-col :class="shouldExpanded ? 'min-h-30' : ''"> <div relative flex-1 flex flex-col :class="shouldExpanded ? 'min-h-30' : ''">
<EditorContent <EditorContent
:editor="editor" flex max-w-full :editor="editor" flex max-w-full
@ -516,7 +533,7 @@ function stopQuestionMarkPropagation(e: KeyboardEvent) {
p2 p2
type="datetime-local" type="datetime-local"
name="schedule-datetime" name="schedule-datetime"
:min="minimumScheduledTime" :min="getDatetimeInputFormat(minimumScheduledTime)"
> >
</template> </template>
</CommonDropdown> </CommonDropdown>
@ -582,7 +599,8 @@ function stopQuestionMarkPropagation(e: KeyboardEvent) {
<button <button
v-if="!threadIsActive || isFinalItemOfThread" v-if="!threadIsActive || isFinalItemOfThread"
btn-solid rounded-3 text-sm w-full flex="~ gap1" items-center md:w-fit class="publish-button" btn-solid rounded-3 text-sm w-full flex="~ gap1" items-center md:w-fit class="publish-button"
:aria-disabled="isPublishDisabled || isExceedingCharacterLimit" aria-describedby="publish-tooltip" :aria-disabled="isPublishDisabled || isExceedingCharacterLimit || !isValidScheduledTime"
aria-describedby="publish-tooltip"
@click="publish" @click="publish"
> >
<span v-if="isSending" block animate-spin preserve-3d> <span v-if="isSending" block animate-spin preserve-3d>
@ -596,8 +614,8 @@ function stopQuestionMarkPropagation(e: KeyboardEvent) {
</template> </template>
<template v-else> <template v-else>
<span v-if="draft.editingStatus">{{ $t('action.save_changes') }}</span> <span v-if="draft.editingStatus">{{ $t('action.save_changes') }}</span>
<span v-else-if="draft.params.inReplyToId">{{ $t('action.reply') }}</span>
<span v-else-if="scheduledTime">{{ !isSending ? $t('action.schedule') : $t('state.scheduling') }}</span> <span v-else-if="scheduledTime">{{ !isSending ? $t('action.schedule') : $t('state.scheduling') }}</span>
<span v-else-if="draft.params.inReplyToId">{{ $t('action.reply') }}</span>
<span v-else>{{ !isSending ? $t('action.publish') : $t('state.publishing') }}</span> <span v-else>{{ !isSending ? $t('action.publish') : $t('state.publishing') }}</span>
</template> </template>
</button> </button>

Wyświetl plik

@ -615,6 +615,7 @@
"publishing": "Publishing", "publishing": "Publishing",
"save_failed": "Save failed", "save_failed": "Save failed",
"schedule_failed": "Schedule failed", "schedule_failed": "Schedule failed",
"schedule_time_invalid": "The scheduled time must be at least 5 minutes later in the future. Set to {0} or later.",
"scheduling": "Scheduling", "scheduling": "Scheduling",
"upload_failed": "Upload failed", "upload_failed": "Upload failed",
"uploading": "Uploading..." "uploading": "Uploading..."