From 46c217446acecd93ebd0cd04e3daf301049343e9 Mon Sep 17 00:00:00 2001 From: amhsirak Date: Mon, 13 Oct 2025 17:14:02 +0530 Subject: [PATCH] feat: sync dark mode bg navbar --- src/components/dashboard/NavBar.tsx | 2 +- src/components/robot/RobotDuplicate.tsx | 172 ------- src/components/robot/RobotEdit.tsx | 586 ---------------------- src/components/robot/RobotSettings.tsx | 173 ------- src/components/robot/ScheduleSettings.tsx | 314 ------------ 5 files changed, 1 insertion(+), 1246 deletions(-) delete mode 100644 src/components/robot/RobotDuplicate.tsx delete mode 100644 src/components/robot/RobotEdit.tsx delete mode 100644 src/components/robot/RobotSettings.tsx delete mode 100644 src/components/robot/ScheduleSettings.tsx diff --git a/src/components/dashboard/NavBar.tsx b/src/components/dashboard/NavBar.tsx index 24e11d09..7526de70 100644 --- a/src/components/dashboard/NavBar.tsx +++ b/src/components/dashboard/NavBar.tsx @@ -601,7 +601,7 @@ export const NavBar: React.FC = ({ const NavBarWrapper = styled.div<{ mode: 'light' | 'dark' }>` grid-area: navbar; - background-color: ${({ mode }) => (mode === 'dark' ? '#1e2124' : '#ffffff')}; + background-color: ${({ mode }) => (mode === 'dark' ? '#080808ff' : '#ffffff')}; padding: 5px; display: flex; justify-content: space-between; diff --git a/src/components/robot/RobotDuplicate.tsx b/src/components/robot/RobotDuplicate.tsx deleted file mode 100644 index bee1ef5b..00000000 --- a/src/components/robot/RobotDuplicate.tsx +++ /dev/null @@ -1,172 +0,0 @@ -import React, { useState, useEffect } from 'react'; -import { GenericModal } from "../ui/GenericModal"; -import { TextField, Typography, Box, Button } from "@mui/material"; -import { modalStyle } from "../recorder/AddWhereCondModal"; -import { useGlobalInfoStore } from '../../context/globalInfo'; -import { duplicateRecording, getStoredRecording } from '../../api/storage'; -import { WhereWhatPair } from 'maxun-core'; -import { useTranslation } from 'react-i18next'; - -interface RobotMeta { - name: string; - id: string; - createdAt: string; - pairs: number; - updatedAt: string; - params: any[]; -} - -interface RobotWorkflow { - workflow: WhereWhatPair[]; -} - -interface ScheduleConfig { - runEvery: number; - runEveryUnit: 'MINUTES' | 'HOURS' | 'DAYS' | 'WEEKS' | 'MONTHS'; - startFrom: 'SUNDAY' | 'MONDAY' | 'TUESDAY' | 'WEDNESDAY' | 'THURSDAY' | 'FRIDAY' | 'SATURDAY'; - atTimeStart?: string; - atTimeEnd?: string; - timezone: string; - lastRunAt?: Date; - nextRunAt?: Date; - cronExpression?: string; -} - -export interface RobotSettings { - id: string; - userId?: number; - recording_meta: RobotMeta; - recording: RobotWorkflow; - google_sheet_email?: string | null; - google_sheet_name?: string | null; - google_sheet_id?: string | null; - google_access_token?: string | null; - google_refresh_token?: string | null; - schedule?: ScheduleConfig | null; -} - -interface RobotSettingsProps { - isOpen: boolean; - handleStart: (settings: RobotSettings) => void; - handleClose: () => void; - initialSettings?: RobotSettings | null; - -} - -export const RobotDuplicationModal = ({ isOpen, handleStart, handleClose, initialSettings }: RobotSettingsProps) => { - const { t } = useTranslation(); - const [targetUrl, setTargetUrl] = useState(''); - const [robot, setRobot] = useState(null); - const { recordingId, notify, setRerenderRobots } = useGlobalInfoStore(); - - useEffect(() => { - if (isOpen) { - getRobot(); - } - }, [isOpen]); - - useEffect(() => { - if (robot) { - const lastPair = robot?.recording.workflow[robot?.recording.workflow.length - 1]; - const url = lastPair?.what.find(action => action.action === "goto")?.args?.[0]; - setTargetUrl(url); - } - }, [robot]); - - const getRobot = async () => { - if (recordingId) { - const robot = await getStoredRecording(recordingId); - setRobot(robot); - } else { - notify('error', t('robot_duplication.notifications.robot_not_found')); - } - } - - const handleTargetUrlChange = (e: React.ChangeEvent) => { - setTargetUrl(e.target.value); - }; - - const handleSave = async () => { - if (!robot || !targetUrl) { - notify('error', t('robot_duplication.notifications.url_required')); - return; - } - - try { - const success = await duplicateRecording(robot.recording_meta.id, targetUrl); - - if (success) { - setRerenderRobots(true); - - notify('success', t('robot_duplication.notifications.duplicate_success')); - handleStart(robot); - handleClose(); - } else { - notify('error', t('robot_duplication.notifications.duplicate_error')); - } - } catch (error) { - notify('error', t('robot_duplication.notifications.unknown_error')); - console.error('Error updating Target URL:', error); - } - }; - - return ( - - <> - - {t('robot_duplication.title')} - - - { - robot && ( - <> - - {t('robot_duplication.descriptions.purpose')} - -
- producthunt.com/topics/api', - url2: 'producthunt.com/topics/database' - }) - }} /> -
- - {t('robot_duplication.descriptions.warning')} - - - - - - - - ) - } -
- -
- ); -}; diff --git a/src/components/robot/RobotEdit.tsx b/src/components/robot/RobotEdit.tsx deleted file mode 100644 index 3b110ba1..00000000 --- a/src/components/robot/RobotEdit.tsx +++ /dev/null @@ -1,586 +0,0 @@ -import React, { useState, useEffect } from 'react'; -import { useTranslation } from 'react-i18next'; -import { GenericModal } from "../ui/GenericModal"; -import { TextField, Typography, Box, Button, IconButton, InputAdornment } from "@mui/material"; -import { Visibility, VisibilityOff } from '@mui/icons-material'; -import { modalStyle } from "../recorder/AddWhereCondModal"; -import { useGlobalInfoStore } from '../../context/globalInfo'; -import { getStoredRecording, updateRecording } from '../../api/storage'; -import { WhereWhatPair } from 'maxun-core'; - -interface RobotMeta { - name: string; - id: string; - createdAt: string; - pairs: number; - updatedAt: string; - params: any[]; -} - -interface RobotWorkflow { - workflow: WhereWhatPair[]; -} - -interface ScheduleConfig { - runEvery: number; - runEveryUnit: 'MINUTES' | 'HOURS' | 'DAYS' | 'WEEKS' | 'MONTHS'; - startFrom: 'SUNDAY' | 'MONDAY' | 'TUESDAY' | 'WEDNESDAY' | 'THURSDAY' | 'FRIDAY' | 'SATURDAY'; - atTimeStart?: string; - atTimeEnd?: string; - timezone: string; - lastRunAt?: Date; - nextRunAt?: Date; - cronExpression?: string; -} - -export interface RobotSettings { - id: string; - userId?: number; - recording_meta: RobotMeta; - recording: RobotWorkflow; - google_sheet_email?: string | null; - google_sheet_name?: string | null; - google_sheet_id?: string | null; - google_access_token?: string | null; - google_refresh_token?: string | null; - schedule?: ScheduleConfig | null; -} - -interface RobotSettingsProps { - isOpen: boolean; - handleStart: (settings: RobotSettings) => void; - handleClose: () => void; - initialSettings?: RobotSettings | null; -} - -interface CredentialInfo { - value: string; - type: string; -} - -interface Credentials { - [key: string]: CredentialInfo; -} - -interface CredentialVisibility { - [key: string]: boolean; -} - -interface GroupedCredentials { - passwords: string[]; - emails: string[]; - usernames: string[]; - others: string[]; -} - -interface ScrapeListLimit { - pairIndex: number; - actionIndex: number; - argIndex: number; - currentLimit: number; -} - -export const RobotEditModal = ({ isOpen, handleStart, handleClose, initialSettings }: RobotSettingsProps) => { - const { t } = useTranslation(); - const [credentials, setCredentials] = useState({}); - const { recordingId, notify, setRerenderRobots } = useGlobalInfoStore(); - const [robot, setRobot] = useState(null); - const [credentialGroups, setCredentialGroups] = useState({ - passwords: [], - emails: [], - usernames: [], - others: [] - }); - const [showPasswords, setShowPasswords] = useState({}); - const [scrapeListLimits, setScrapeListLimits] = useState([]); - - const isEmailPattern = (value: string): boolean => { - return value.includes('@'); - }; - - const isUsernameSelector = (selector: string): boolean => { - return selector.toLowerCase().includes('username') || - selector.toLowerCase().includes('user') || - selector.toLowerCase().includes('email'); - }; - - const determineCredentialType = (selector: string, info: CredentialInfo): 'password' | 'email' | 'username' | 'other' => { - if (info.type === 'password' || selector.toLowerCase().includes('password')) { - return 'password'; - } - if (isEmailPattern(info.value) || selector.toLowerCase().includes('email')) { - return 'email'; - } - if (isUsernameSelector(selector)) { - return 'username'; - } - return 'other'; - }; - - useEffect(() => { - if (isOpen) { - getRobot(); - } - }, [isOpen]); - - useEffect(() => { - if (robot?.recording?.workflow) { - const extractedCredentials = extractInitialCredentials(robot.recording.workflow); - setCredentials(extractedCredentials); - setCredentialGroups(groupCredentialsByType(extractedCredentials)); - - findScrapeListLimits(robot.recording.workflow); - } - }, [robot]); - - const findScrapeListLimits = (workflow: WhereWhatPair[]) => { - const limits: ScrapeListLimit[] = []; - - workflow.forEach((pair, pairIndex) => { - if (!pair.what) return; - - pair.what.forEach((action, actionIndex) => { - if (action.action === 'scrapeList' && action.args && action.args.length > 0) { - // Check if first argument has a limit property - const arg = action.args[0]; - if (arg && typeof arg === 'object' && 'limit' in arg) { - limits.push({ - pairIndex, - actionIndex, - argIndex: 0, - currentLimit: arg.limit - }); - } - } - }); - }); - - setScrapeListLimits(limits); - }; - - function extractInitialCredentials(workflow: any[]): Credentials { - const credentials: Credentials = {}; - - const isPrintableCharacter = (char: string): boolean => { - return char.length === 1 && !!char.match(/^[\x20-\x7E]$/); - }; - - workflow.forEach(step => { - if (!step.what) return; - - let currentSelector = ''; - let currentValue = ''; - let currentType = ''; - let i = 0; - - while (i < step.what.length) { - const action = step.what[i]; - - if (!action.action || !action.args?.[0]) { - i++; - continue; - } - - const selector = action.args[0]; - - // Handle full word type actions first - if (action.action === 'type' && - action.args?.length >= 2 && - typeof action.args[1] === 'string' && - action.args[1].length > 1) { - - if (!credentials[selector]) { - credentials[selector] = { - value: action.args[1], - type: action.args[2] || 'text' - }; - } - i++; - continue; - } - - // Handle character-by-character sequences (both type and press) - if ((action.action === 'type' || action.action === 'press') && - action.args?.length >= 2 && - typeof action.args[1] === 'string') { - - if (selector !== currentSelector) { - if (currentSelector && currentValue) { - credentials[currentSelector] = { - value: currentValue, - type: currentType || 'text' - }; - } - currentSelector = selector; - currentValue = credentials[selector]?.value || ''; - currentType = action.args[2] || credentials[selector]?.type || 'text'; - } - - const character = action.args[1]; - - if (isPrintableCharacter(character)) { - currentValue += character; - } else if (character === 'Backspace') { - currentValue = currentValue.slice(0, -1); - } - - if (!currentType && action.args[2]?.toLowerCase() === 'password') { - currentType = 'password'; - } - - let j = i + 1; - while (j < step.what.length) { - const nextAction = step.what[j]; - if (!nextAction.action || !nextAction.args?.[0] || - nextAction.args[0] !== selector || - (nextAction.action !== 'type' && nextAction.action !== 'press')) { - break; - } - if (nextAction.args[1] === 'Backspace') { - currentValue = currentValue.slice(0, -1); - } else if (isPrintableCharacter(nextAction.args[1])) { - currentValue += nextAction.args[1]; - } - j++; - } - - credentials[currentSelector] = { - value: currentValue, - type: currentType - }; - - i = j; - } else { - i++; - } - } - - if (currentSelector && currentValue) { - credentials[currentSelector] = { - value: currentValue, - type: currentType || 'text' - }; - } - }); - - return credentials; - } - - const groupCredentialsByType = (credentials: Credentials): GroupedCredentials => { - return Object.entries(credentials).reduce((acc: GroupedCredentials, [selector, info]) => { - const credentialType = determineCredentialType(selector, info); - - switch (credentialType) { - case 'password': - acc.passwords.push(selector); - break; - case 'email': - acc.emails.push(selector); - break; - case 'username': - acc.usernames.push(selector); - break; - default: - acc.others.push(selector); - } - - return acc; - }, { passwords: [], emails: [], usernames: [], others: [] }); - }; - - const getRobot = async () => { - if (recordingId) { - const robot = await getStoredRecording(recordingId); - setRobot(robot); - } else { - notify('error', t('robot_edit.notifications.update_failed')); - } - }; - - const handleClickShowPassword = (selector: string) => { - setShowPasswords(prev => ({ - ...prev, - [selector]: !prev[selector] - })); - }; - - const handleRobotNameChange = (newName: string) => { - setRobot((prev) => - prev ? { ...prev, recording_meta: { ...prev.recording_meta, name: newName } } : prev - ); - }; - - const handleCredentialChange = (selector: string, value: string) => { - setCredentials(prev => ({ - ...prev, - [selector]: { - ...prev[selector], - value - } - })); - }; - - const handleLimitChange = (pairIndex: number, actionIndex: number, argIndex: number, newLimit: number) => { - setRobot((prev) => { - if (!prev) return prev; - - const updatedWorkflow = [...prev.recording.workflow]; - if ( - updatedWorkflow.length > pairIndex && - updatedWorkflow[pairIndex]?.what && - updatedWorkflow[pairIndex].what.length > actionIndex && - updatedWorkflow[pairIndex].what[actionIndex].args && - updatedWorkflow[pairIndex].what[actionIndex].args.length > argIndex - ) { - updatedWorkflow[pairIndex].what[actionIndex].args[argIndex].limit = newLimit; - - setScrapeListLimits(prev => { - return prev.map(item => { - if (item.pairIndex === pairIndex && - item.actionIndex === actionIndex && - item.argIndex === argIndex) { - return { ...item, currentLimit: newLimit }; - } - return item; - }); - }); - } - - return { ...prev, recording: { ...prev.recording, workflow: updatedWorkflow } }; - }); - }; - - const handleTargetUrlChange = (newUrl: string) => { - setRobot((prev) => { - if (!prev) return prev; - - const updatedWorkflow = [...prev.recording.workflow]; - const lastPairIndex = updatedWorkflow.length - 1; - - if (lastPairIndex >= 0) { - const gotoAction = updatedWorkflow[lastPairIndex]?.what?.find(action => action.action === "goto"); - if (gotoAction && gotoAction.args && gotoAction.args.length > 0) { - gotoAction.args[0] = newUrl; - } - } - - return { ...prev, recording: { ...prev.recording, workflow: updatedWorkflow } }; - }); - }; - - const renderAllCredentialFields = () => { - return ( - <> - {renderCredentialFields( - credentialGroups.usernames, - t('Username'), - 'text' - )} - - {renderCredentialFields( - credentialGroups.emails, - t('Email'), - 'text' - )} - - {renderCredentialFields( - credentialGroups.passwords, - t('Password'), - 'password' - )} - - {renderCredentialFields( - credentialGroups.others, - t('Other'), - 'text' - )} - - ); - }; - - const renderCredentialFields = (selectors: string[], headerText: string, defaultType: 'text' | 'password' = 'text') => { - if (selectors.length === 0) return null; - - return ( - <> - {selectors.map((selector, index) => { - const isVisible = showPasswords[selector]; - - return ( - handleCredentialChange(selector, e.target.value)} - style={{ marginBottom: '20px' }} - InputProps={{ - endAdornment: ( - - handleClickShowPassword(selector)} - edge="end" - disabled={!credentials[selector]?.value} - > - {isVisible ? : } - - - ), - }} - /> - ); - })} - - ); - }; - - const renderScrapeListLimitFields = () => { - if (scrapeListLimits.length === 0) return null; - - return ( - <> - - {t('List Limits')} - - - {scrapeListLimits.map((limitInfo, index) => ( - { - const value = parseInt(e.target.value, 10); - if (value >= 1) { - handleLimitChange( - limitInfo.pairIndex, - limitInfo.actionIndex, - limitInfo.argIndex, - value - ); - } - }} - inputProps={{ min: 1 }} - style={{ marginBottom: '20px' }} - /> - ))} - - ); - }; - - const handleSave = async () => { - if (!robot) return; - - try { - const credentialsForPayload = Object.entries(credentials).reduce((acc, [selector, info]) => { - const enforceType = info.type === 'password' ? 'password' : 'text'; - - acc[selector] = { - value: info.value, - type: enforceType - }; - return acc; - }, {} as Record); - - const lastPair = robot.recording.workflow[robot.recording.workflow.length - 1]; - const targetUrl = lastPair?.what.find(action => action.action === "goto")?.args?.[0]; - - const payload = { - name: robot.recording_meta.name, - limits: scrapeListLimits.map(limit => ({ - pairIndex: limit.pairIndex, - actionIndex: limit.actionIndex, - argIndex: limit.argIndex, - limit: limit.currentLimit - })), - credentials: credentialsForPayload, - targetUrl: targetUrl, - }; - - const success = await updateRecording(robot.recording_meta.id, payload); - - if (success) { - setRerenderRobots(true); - - notify('success', t('robot_edit.notifications.update_success')); - handleStart(robot); - handleClose(); - } else { - notify('error', t('robot_edit.notifications.update_failed')); - } - } catch (error) { - notify('error', t('robot_edit.notifications.update_error')); - console.error('Error updating robot:', error); - } - }; - - const lastPair = robot?.recording.workflow[robot?.recording.workflow.length - 1]; - const targetUrl = lastPair?.what.find(action => action.action === "goto")?.args?.[0]; - - return ( - - <> - - {t('robot_edit.title')} - - - {robot && ( - <> - handleRobotNameChange(e.target.value)} - style={{ marginBottom: '20px' }} - /> - - handleTargetUrlChange(e.target.value)} - style={{ marginBottom: '20px' }} - /> - - {renderScrapeListLimitFields()} - - {(Object.keys(credentials).length > 0) && ( - <> - - {t('Input Texts')} - - {renderAllCredentialFields()} - - )} - - - - - - - )} - - - - ); -}; \ No newline at end of file diff --git a/src/components/robot/RobotSettings.tsx b/src/components/robot/RobotSettings.tsx deleted file mode 100644 index c91b4f11..00000000 --- a/src/components/robot/RobotSettings.tsx +++ /dev/null @@ -1,173 +0,0 @@ -import React, { useState, useEffect } from 'react'; -import { useTranslation } from 'react-i18next'; -import { GenericModal } from "../ui/GenericModal"; -import { TextField, Typography, Box } from "@mui/material"; -import { useGlobalInfoStore } from '../../context/globalInfo'; -import { getStoredRecording } from '../../api/storage'; -import { WhereWhatPair } from 'maxun-core'; -import { getUserById } from "../../api/auth"; - -interface RobotMeta { - name: string; - id: string; - createdAt: string; - pairs: number; - updatedAt: string; - params: any[]; -} - -interface RobotWorkflow { - workflow: WhereWhatPair[]; -} - -interface ScheduleConfig { - runEvery: number; - runEveryUnit: 'MINUTES' | 'HOURS' | 'DAYS' | 'WEEKS' | 'MONTHS'; - startFrom: 'SUNDAY' | 'MONDAY' | 'TUESDAY' | 'WEDNESDAY' | 'THURSDAY' | 'FRIDAY' | 'SATURDAY'; - atTimeStart?: string; - atTimeEnd?: string; - timezone: string; - lastRunAt?: Date; - nextRunAt?: Date; - cronExpression?: string; -} - -export interface RobotSettings { - id: string; - userId?: number; - recording_meta: RobotMeta; - recording: RobotWorkflow; - google_sheet_email?: string | null; - google_sheet_name?: string | null; - google_sheet_id?: string | null; - google_access_token?: string | null; - google_refresh_token?: string | null; - schedule?: ScheduleConfig | null; -} - -interface RobotSettingsProps { - isOpen: boolean; - handleStart: (settings: RobotSettings) => void; - handleClose: () => void; - initialSettings?: RobotSettings | null; -} - -export const RobotSettingsModal = ({ isOpen, handleStart, handleClose, initialSettings }: RobotSettingsProps) => { - const { t } = useTranslation(); - const [userEmail, setUserEmail] = useState(null); - const [robot, setRobot] = useState(null); - const { recordingId, notify } = useGlobalInfoStore(); - - useEffect(() => { - if (isOpen) { - getRobot(); - } - }, [isOpen]); - - const getRobot = async () => { - if (recordingId) { - const robot = await getStoredRecording(recordingId); - setRobot(robot); - } else { - notify('error', t('robot_settings.errors.robot_not_found')); - } - } - - const lastPair = robot?.recording.workflow[robot?.recording.workflow.length - 1]; - - // Find the `goto` action in `what` and retrieve its arguments - const targetUrl = lastPair?.what.find(action => action.action === "goto")?.args?.[0]; - - useEffect(() => { - const fetchUserEmail = async () => { - if (robot && robot.userId) { - const userData = await getUserById(robot.userId.toString()); - if (userData && userData.user) { - setUserEmail(userData.user.email); - } - } - }; - fetchUserEmail(); - }, [robot?.userId]); - - return ( - - <> - - {t('robot_settings.title')} - - - { - robot && ( - <> - - - {robot.recording.workflow?.[0]?.what?.[0]?.args?.[0]?.limit !== undefined && ( - - )} - - - - ) - } - - - - ); -}; - -export const modalStyle = { -top: "50%", -left: "50%", -transform: "translate(-50%, -50%)", -width: "30%", -backgroundColor: "background.paper", -p: 4, -height: "fit-content", -display: "block", -padding: "20px", -}; diff --git a/src/components/robot/ScheduleSettings.tsx b/src/components/robot/ScheduleSettings.tsx deleted file mode 100644 index 7a28d2dc..00000000 --- a/src/components/robot/ScheduleSettings.tsx +++ /dev/null @@ -1,314 +0,0 @@ -import React, { useState, useEffect } from 'react'; -import { useTranslation } from 'react-i18next'; -import { GenericModal } from "../ui/GenericModal"; -import { MenuItem, TextField, Typography, Box } from "@mui/material"; -import { Dropdown } from "../ui/DropdownMui"; -import Button from "@mui/material/Button"; -import { validMomentTimezones } from '../../constants/const'; -import { useGlobalInfoStore } from '../../context/globalInfo'; -import { getSchedule, deleteSchedule } from '../../api/storage'; - -interface ScheduleSettingsProps { - isOpen: boolean; - handleStart: (settings: ScheduleSettings) => Promise; - handleClose: () => void; - initialSettings?: ScheduleSettings | null; -} - -export interface ScheduleSettings { - runEvery: number; - runEveryUnit: string; - startFrom: string; - dayOfMonth?: string; - atTimeStart?: string; - atTimeEnd?: string; - timezone: string; -} - -export const ScheduleSettingsModal = ({ isOpen, handleStart, handleClose, initialSettings }: ScheduleSettingsProps) => { - const { t } = useTranslation(); - const [schedule, setSchedule] = useState(null); - const [settings, setSettings] = useState({ - runEvery: 1, - runEveryUnit: 'HOURS', - startFrom: 'MONDAY', - dayOfMonth: '1', - atTimeStart: '00:00', - atTimeEnd: '01:00', - timezone: 'UTC' - }); - - useEffect(() => { - if (initialSettings) { - setSettings(initialSettings); - } - }, [initialSettings]); - - const handleChange = (field: keyof ScheduleSettings, value: string | number | boolean) => { - setSettings(prev => ({ ...prev, [field]: value })); - }; - - const textStyle = { - width: '150px', - height: '52px', - marginRight: '10px', - }; - - const dropDownStyle = { - marginTop: '2px', - width: '150px', - height: '59px', - marginRight: '10px', - }; - - const units = [ - 'MINUTES', - 'HOURS', - 'DAYS', - 'WEEKS', - 'MONTHS' - ]; - - const days = [ - 'MONDAY', - 'TUESDAY', - 'WEDNESDAY', - 'THURSDAY', - 'FRIDAY', - 'SATURDAY', - 'SUNDAY' - ]; - - const { recordingId, notify } = useGlobalInfoStore(); - - const deleteRobotSchedule = () => { - if (recordingId) { - deleteSchedule(recordingId); - setSchedule(null); - notify('success', t('Schedule deleted successfully')); - } else { - console.error('No recording id provided'); - } - - setSettings({ - runEvery: 1, - runEveryUnit: 'HOURS', - startFrom: 'MONDAY', - dayOfMonth: '', - atTimeStart: '00:00', - atTimeEnd: '01:00', - timezone: 'UTC' - }); - }; - - const getRobotSchedule = async () => { - if (recordingId) { - const scheduleData = await getSchedule(recordingId); - setSchedule(scheduleData); - } else { - console.error('No recording id provided'); - } - } - - useEffect(() => { - if (isOpen) { - const fetchSchedule = async () => { - await getRobotSchedule(); - }; - fetchSchedule(); - } - }, [isOpen]); - - const getDayOrdinal = (day: string | undefined) => { - if (!day) return ''; - const lastDigit = day.slice(-1); - const lastTwoDigits = day.slice(-2); - - // Special cases for 11, 12, 13 - if (['11', '12', '13'].includes(lastTwoDigits)) { - return t('schedule_settings.labels.on_day.th'); - } - - // Other cases - switch (lastDigit) { - case '1': return t('schedule_settings.labels.on_day.st'); - case '2': return t('schedule_settings.labels.on_day.nd'); - case '3': return t('schedule_settings.labels.on_day.rd'); - default: return t('schedule_settings.labels.on_day.th'); - } - }; - - return ( - - *': { marginBottom: '20px' }, - }}> - {t('schedule_settings.title')} - <> - {schedule !== null ? ( - <> - {t('schedule_settings.run_every')}: {schedule.runEvery} {schedule.runEveryUnit.toLowerCase()} - {['MONTHS', 'WEEKS'].includes(settings.runEveryUnit) ? t('schedule_settings.start_from') : t('schedule_settings.start_from')}: {schedule.startFrom.charAt(0).toUpperCase() + schedule.startFrom.slice(1).toLowerCase()} - {schedule.runEveryUnit === 'MONTHS' && ( - {t('schedule_settings.on_day')}: {schedule.dayOfMonth}{getDayOrdinal(schedule.dayOfMonth)} of the month - )} - {t('schedule_settings.at_around')}: {schedule.atTimeStart}, {schedule.timezone} {t('schedule_settings.timezone')} - - - - - ) : ( - <> - - {t('schedule_settings.labels.run_once_every')} - handleChange('runEvery', parseInt(e.target.value))} - sx={textStyle} - inputProps={{ min: 1 }} - /> - handleChange('runEveryUnit', e.target.value)} - sx={dropDownStyle} - > - {units.map((unit) => ( - {unit.charAt(0).toUpperCase() + unit.slice(1).toLowerCase()} - ))} - - - - - - {['MONTHS', 'WEEKS'].includes(settings.runEveryUnit) ? t('schedule_settings.labels.start_from_label') : t('schedule_settings.labels.start_from_label')} - - handleChange('startFrom', e.target.value)} - sx={dropDownStyle} - > - {days.map((day) => ( - - {day.charAt(0).toUpperCase() + day.slice(1).toLowerCase()} - - ))} - - - - {settings.runEveryUnit === 'MONTHS' && ( - - {t('schedule_settings.labels.on_day_of_month')} - handleChange('dayOfMonth', e.target.value)} - sx={textStyle} - inputProps={{ min: 1, max: 31 }} - /> - - )} - - {['MINUTES', 'HOURS'].includes(settings.runEveryUnit) ? ( - - - {t('schedule_settings.labels.in_between')} - handleChange('atTimeStart', e.target.value)} - sx={textStyle} - /> - handleChange('atTimeEnd', e.target.value)} - sx={textStyle} - /> - - - ) : ( - - {t('schedule_settings.at_around')} - handleChange('atTimeStart', e.target.value)} - sx={textStyle} - /> - - )} - - - {t('schedule_settings.timezone')} - handleChange('timezone', e.target.value)} - sx={dropDownStyle} - > - {validMomentTimezones.map((tz) => ( - {tz.charAt(0).toUpperCase() + tz.slice(1).toLowerCase()} - ))} - - - - - - - - )} - - - - ); -}; - -const modalStyle = { - top: '50%', - left: '50%', - transform: 'translate(-50%, -50%)', - width: '40%', - backgroundColor: 'background.paper', - p: 4, - height: 'fit-content', - display: 'block', - padding: '20px', -}; \ No newline at end of file