refactor: standardize task and recurrence type strings to lowercase across components and services

This commit is contained in:
JSC
2025-08-29 00:39:00 +02:00
parent 009780e64c
commit 4251057668
4 changed files with 52 additions and 40 deletions

View File

@@ -35,8 +35,8 @@ interface CreateTaskDialogProps {
onCancel: () => void onCancel: () => void
} }
const TASK_TYPES: TaskType[] = ['CREDIT_RECHARGE', 'PLAY_SOUND', 'PLAY_PLAYLIST'] const TASK_TYPES: TaskType[] = ['credit_recharge', 'play_sound', 'play_playlist']
const RECURRENCE_TYPES: RecurrenceType[] = ['NONE', 'HOURLY', 'DAILY', 'WEEKLY', 'MONTHLY', 'YEARLY', 'CRON'] const RECURRENCE_TYPES: RecurrenceType[] = ['none', 'hourly', 'daily', 'weekly', 'monthly', 'yearly', 'cron']
export function CreateTaskDialog({ export function CreateTaskDialog({
open, open,
@@ -49,11 +49,11 @@ export function CreateTaskDialog({
const [formData, setFormData] = useState<CreateScheduledTaskRequest>({ const [formData, setFormData] = useState<CreateScheduledTaskRequest>({
name: '', name: '',
task_type: 'PLAY_SOUND', task_type: 'play_sound',
scheduled_at: '', scheduled_at: '',
timezone: timezone, timezone: timezone,
parameters: {}, parameters: {},
recurrence_type: 'NONE', recurrence_type: 'none',
cron_expression: null, cron_expression: null,
recurrence_count: null, recurrence_count: null,
expires_at: null, expires_at: null,
@@ -68,9 +68,21 @@ export function CreateTaskDialog({
// Validate parameters JSON // Validate parameters JSON
try { try {
const parameters = JSON.parse(parametersJson) const parameters = JSON.parse(parametersJson)
// Send the datetime as UTC to prevent backend timezone conversion
// The user's selected time should be stored exactly as entered
let scheduledAt = formData.scheduled_at
if (scheduledAt.length === 16) {
scheduledAt += ':00' // Add seconds if missing
}
// Add Z to indicate this is already UTC time, preventing backend conversion
const scheduledAtUTC = scheduledAt + 'Z'
onSubmit({ onSubmit({
...formData, ...formData,
parameters, parameters,
scheduled_at: scheduledAtUTC,
}) })
} catch { } catch {
setParametersError('Invalid JSON format') setParametersError('Invalid JSON format')
@@ -95,11 +107,11 @@ export function CreateTaskDialog({
// Reset form // Reset form
setFormData({ setFormData({
name: '', name: '',
task_type: 'PLAY_SOUND', task_type: 'play_sound',
scheduled_at: '', scheduled_at: '',
timezone: timezone, timezone: timezone,
parameters: {}, parameters: {},
recurrence_type: 'NONE', recurrence_type: 'none',
cron_expression: null, cron_expression: null,
recurrence_count: null, recurrence_count: null,
expires_at: null, expires_at: null,
@@ -114,7 +126,7 @@ export function CreateTaskDialog({
now.setMinutes(now.getMinutes() + 10) // Default to 10 minutes from now now.setMinutes(now.getMinutes() + 10) // Default to 10 minutes from now
// Format the time in the user's timezone // Format the time in the user's timezone
const formatter = new Intl.DateTimeFormat('fr-FR', { const formatter = new Intl.DateTimeFormat('en-US', {
timeZone: timezone, timeZone: timezone,
year: 'numeric', year: 'numeric',
month: '2-digit', month: '2-digit',
@@ -230,7 +242,7 @@ export function CreateTaskDialog({
</Select> </Select>
</div> </div>
{formData.recurrence_type === 'CRON' && ( {formData.recurrence_type === 'cron' && (
<div className="space-y-2"> <div className="space-y-2">
<Label htmlFor="cron_expression">Cron Expression</Label> <Label htmlFor="cron_expression">Cron Expression</Label>
<Input <Input
@@ -242,7 +254,7 @@ export function CreateTaskDialog({
</div> </div>
)} )}
{formData.recurrence_type !== 'NONE' && formData.recurrence_type !== 'CRON' && ( {formData.recurrence_type !== 'none' && formData.recurrence_type !== 'cron' && (
<div className="space-y-2"> <div className="space-y-2">
<Label htmlFor="recurrence_count">Max Executions</Label> <Label htmlFor="recurrence_count">Max Executions</Label>
<Input <Input

View File

@@ -33,8 +33,8 @@ interface SchedulersHeaderProps {
taskCount: number taskCount: number
} }
const TASK_STATUSES: TaskStatus[] = ['PENDING', 'RUNNING', 'COMPLETED', 'FAILED', 'CANCELLED'] const TASK_STATUSES: TaskStatus[] = ['pending', 'running', 'completed', 'failed', 'cancelled']
const TASK_TYPES: TaskType[] = ['CREDIT_RECHARGE', 'PLAY_SOUND', 'PLAY_PLAYLIST'] const TASK_TYPES: TaskType[] = ['credit_recharge', 'play_sound', 'play_playlist']
export function SchedulersHeader({ export function SchedulersHeader({
searchQuery, searchQuery,

View File

@@ -102,7 +102,7 @@ export function SchedulersTable({ tasks, onTaskUpdated, onTaskDeleted }: Schedul
</div> </div>
<p className="text-sm text-muted-foreground"> <p className="text-sm text-muted-foreground">
{getTaskTypeLabel(task.task_type)} {getTaskTypeLabel(task.task_type)}
{task.recurrence_type !== 'NONE' && ( {task.recurrence_type !== 'none' && (
<span className="ml-2"> <span className="ml-2">
{getRecurrenceTypeLabel(task.recurrence_type)} {getRecurrenceTypeLabel(task.recurrence_type)}
</span> </span>
@@ -123,7 +123,7 @@ export function SchedulersTable({ tasks, onTaskUpdated, onTaskDeleted }: Schedul
<DropdownMenuContent align="end"> <DropdownMenuContent align="end">
<DropdownMenuItem <DropdownMenuItem
onClick={() => handleToggleActive(task)} onClick={() => handleToggleActive(task)}
disabled={task.status === 'COMPLETED' || task.status === 'CANCELLED'} disabled={task.status === 'completed' || task.status === 'cancelled'}
> >
{task.is_active ? ( {task.is_active ? (
<> <>
@@ -140,7 +140,7 @@ export function SchedulersTable({ tasks, onTaskUpdated, onTaskDeleted }: Schedul
<DropdownMenuSeparator /> <DropdownMenuSeparator />
<DropdownMenuItem <DropdownMenuItem
onClick={() => handleCancelTask(task)} onClick={() => handleCancelTask(task)}
disabled={task.status === 'COMPLETED' || task.status === 'CANCELLED'} disabled={task.status === 'completed' || task.status === 'cancelled'}
className="text-destructive focus:text-destructive" className="text-destructive focus:text-destructive"
> >
<Square className="h-4 w-4 mr-2" /> <Square className="h-4 w-4 mr-2" />
@@ -165,9 +165,9 @@ export function SchedulersTable({ tasks, onTaskUpdated, onTaskDeleted }: Schedul
<p className="font-medium"> <p className="font-medium">
{task.next_execution_at {task.next_execution_at
? formatDate(task.next_execution_at) ? formatDate(task.next_execution_at)
: task.status === 'COMPLETED' : task.status === 'completed'
? 'Completed' ? 'Completed'
: task.status === 'CANCELLED' : task.status === 'cancelled'
? 'Cancelled' ? 'Cancelled'
: 'N/A'} : 'N/A'}
</p> </p>

View File

@@ -1,12 +1,12 @@
import { apiClient } from '../client' import { apiClient } from '../client'
import type { ApiResponse } from '../types' import type { ApiResponse } from '../types'
// Task types // Task types (backend expects lowercase)
export type TaskType = 'CREDIT_RECHARGE' | 'PLAY_SOUND' | 'PLAY_PLAYLIST' export type TaskType = 'credit_recharge' | 'play_sound' | 'play_playlist'
export type TaskStatus = 'PENDING' | 'RUNNING' | 'COMPLETED' | 'FAILED' | 'CANCELLED' export type TaskStatus = 'pending' | 'running' | 'completed' | 'failed' | 'cancelled'
export type RecurrenceType = 'NONE' | 'HOURLY' | 'DAILY' | 'WEEKLY' | 'MONTHLY' | 'YEARLY' | 'CRON' export type RecurrenceType = 'none' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'cron'
// Task interfaces // Task interfaces
export interface ScheduledTask { export interface ScheduledTask {
@@ -134,11 +134,11 @@ export const schedulersService = {
// Utility functions // Utility functions
export function getTaskTypeLabel(taskType: TaskType): string { export function getTaskTypeLabel(taskType: TaskType): string {
switch (taskType) { switch (taskType) {
case 'CREDIT_RECHARGE': case 'credit_recharge':
return 'Credit Recharge' return 'Credit Recharge'
case 'PLAY_SOUND': case 'play_sound':
return 'Play Sound' return 'Play Sound'
case 'PLAY_PLAYLIST': case 'play_playlist':
return 'Play Playlist' return 'Play Playlist'
default: default:
return taskType return taskType
@@ -147,15 +147,15 @@ export function getTaskTypeLabel(taskType: TaskType): string {
export function getTaskStatusLabel(status: TaskStatus): string { export function getTaskStatusLabel(status: TaskStatus): string {
switch (status) { switch (status) {
case 'PENDING': case 'pending':
return 'Pending' return 'Pending'
case 'RUNNING': case 'running':
return 'Running' return 'Running'
case 'COMPLETED': case 'completed':
return 'Completed' return 'Completed'
case 'FAILED': case 'failed':
return 'Failed' return 'Failed'
case 'CANCELLED': case 'cancelled':
return 'Cancelled' return 'Cancelled'
default: default:
return status return status
@@ -164,19 +164,19 @@ export function getTaskStatusLabel(status: TaskStatus): string {
export function getRecurrenceTypeLabel(recurrenceType: RecurrenceType): string { export function getRecurrenceTypeLabel(recurrenceType: RecurrenceType): string {
switch (recurrenceType) { switch (recurrenceType) {
case 'NONE': case 'none':
return 'None' return 'None'
case 'HOURLY': case 'hourly':
return 'Hourly' return 'Hourly'
case 'DAILY': case 'daily':
return 'Daily' return 'Daily'
case 'WEEKLY': case 'weekly':
return 'Weekly' return 'Weekly'
case 'MONTHLY': case 'monthly':
return 'Monthly' return 'Monthly'
case 'YEARLY': case 'yearly':
return 'Yearly' return 'Yearly'
case 'CRON': case 'cron':
return 'Custom' return 'Custom'
default: default:
return recurrenceType return recurrenceType
@@ -185,15 +185,15 @@ export function getRecurrenceTypeLabel(recurrenceType: RecurrenceType): string {
export function getTaskStatusVariant(status: TaskStatus): 'default' | 'secondary' | 'destructive' | 'outline' { export function getTaskStatusVariant(status: TaskStatus): 'default' | 'secondary' | 'destructive' | 'outline' {
switch (status) { switch (status) {
case 'PENDING': case 'pending':
return 'outline' return 'outline'
case 'RUNNING': case 'running':
return 'default' return 'default'
case 'COMPLETED': case 'completed':
return 'secondary' return 'secondary'
case 'FAILED': case 'failed':
return 'destructive' return 'destructive'
case 'CANCELLED': case 'cancelled':
return 'outline' return 'outline'
default: default:
return 'default' return 'default'