refactor: standardize task and recurrence type strings to lowercase across components and services
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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'
|
||||||
|
|||||||
Reference in New Issue
Block a user