update save config

This commit is contained in:
Admin 2025-09-18 09:30:21 +07:00
parent ce4b3baf3a
commit 6b2d980060
4 changed files with 78 additions and 15 deletions

View File

@ -15,15 +15,15 @@ export const defaultShortcuts: IShortcut[] = [
{
id: uuid(),
links: [
'https://int.ipsupply.com.au/erptools/001_search-vpn?search=${keyword}',
'https://www.ebay.com/sch/i.html?_nkw=${keyword}&_sop=15'
'https://int.ipsupply.com.au/erptools/001_search-vpn?search={keyword}',
'https://www.ebay.com/sch/i.html?_nkw={keyword}&_sop=15'
],
shortcut: 'CommandOrControl+Shift+1'
shortcut: 'Control+Shift+1'
},
{
id: uuid(),
links: ['https://esearch.danielvu.com?keyword=${keyword}'],
shortcut: 'CommandOrControl+Shift+2'
links: ['https://esearch.danielvu.com?keyword={keyword}'],
shortcut: 'Control+Shift+2'
}
]
@ -86,7 +86,7 @@ const handleOpenBrowserByLink = (data: IShortcut) => {
const query = encodeURIComponent(text)
data.links.forEach((link) => {
const url = link.replace(/\$\{keyword\}/g, query) // Thay ${query} trong link
const url = link.replace(/\$\{keyword\}|\{keyword\}/g, query)
console.log(`[${new Date().toLocaleTimeString()}] Opening URL: ${url}`)
shell.openExternal(url) // Mở trong browser mặc định
})

View File

@ -12,6 +12,7 @@ import { getConfigFile, saveConfigFile } from './api/config'
function App(): React.JSX.Element {
const [loading, setLoading] = useState(true)
const [shotcuts, setShotcuts] = useState<IShotcut[]>([])
const [editing, setEditing] = useState<IShotcut | null>(null)
// Hàm lưu config
const saveConfig = async (newShortcuts: IShotcut[]) => {
@ -30,6 +31,21 @@ function App(): React.JSX.Element {
saveConfig(newShortcuts)
}
// Khi nhấn edit từ list
const handleEdit = (shotcut: IShotcut) => {
setEditing(shotcut)
}
// Submit update
const handleUpdate = (updatedShotcut: IShotcut) => {
const updatedList = shotcuts.map((sc) =>
sc.id === updatedShotcut.id ? updatedShotcut : sc
)
setShotcuts(updatedList)
saveConfig(updatedList)
setEditing(null) // reset form
}
// Gọi IPC để lấy dữ liệu config
useEffect(() => {
const fetchData = async () => {
@ -67,15 +83,22 @@ function App(): React.JSX.Element {
>
<Container fluid mt={'lg'}>
<ShotcutForm
shortcuts={shotcuts}
onSubmit={(newItem) => {
const updated = [newItem, ...shotcuts]
setShotcuts(updated)
saveConfig(updated)
}}
editingShotcut={editing || undefined}
onUpdate={handleUpdate}
/>
<Box py={'lg'}>
<ShotcutList shotcuts={shotcuts} onDelete={handleDelete} />
<ShotcutList
onEdit={handleEdit}
shotcuts={shotcuts}
onDelete={handleDelete}
/>
</Box>
<LoadingOverlay

View File

@ -4,6 +4,7 @@ import { ActionIcon, Button, Code, Group, Paper, Stack, Text, TextInput } from '
import { useForm, zodResolver } from '@mantine/form'
import { IShotcut } from '@renderer/types'
import { IconPlus, IconX } from '@tabler/icons-react'
import { useEffect } from 'react'
import { v4 as uuid } from 'uuid'
import * as z from 'zod'
@ -46,11 +47,16 @@ type ShotcutFormValues = z.infer<typeof ShotcutSchema>
interface ShotcutFormProps {
onSubmit: (shotcut: IShotcut) => void
onUpdate?: (shotcut: IShotcut) => void
editingShotcut?: IShotcut
shortcuts: IShotcut[]
}
export function ShotcutForm({ onSubmit }: ShotcutFormProps) {
export function ShotcutForm({ onSubmit, onUpdate, editingShotcut, shortcuts }: ShotcutFormProps) {
const form = useForm<ShotcutFormValues>({
initialValues: { shortcut: '', links: [''] },
initialValues: editingShotcut
? { shortcut: editingShotcut.shortcut, links: editingShotcut.links }
: { shortcut: '', links: [''] },
validate: zodResolver(ShotcutSchema)
})
@ -58,16 +64,41 @@ export function ShotcutForm({ onSubmit }: ShotcutFormProps) {
const removeLink = (index: number) => form.removeListItem('links', index)
const handleSubmit = (values: ShotcutFormValues) => {
onSubmit({ ...values, id: uuid() })
form.reset()
// Kiểm tra trùng shortcut
const isDuplicate = shortcuts.some(
(item) =>
item.shortcut === values.shortcut &&
(!editingShotcut || item.id !== editingShotcut.id)
)
if (isDuplicate) {
form.setFieldError('shortcut', 'Shortcut already exists')
return
}
if (editingShotcut && onUpdate) {
onUpdate({ ...editingShotcut, ...values })
form.reset()
} else {
onSubmit({ ...values, id: uuid() })
form.reset()
}
}
useEffect(() => {
if (!editingShotcut) return
form.setValues(editingShotcut)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [editingShotcut])
return (
<Paper shadow="sm" radius="md" p="md" withBorder maw={600} mx="auto">
<form onSubmit={form.onSubmit(handleSubmit)}>
<Stack>
<Text size="lg" fw={600}>
Create New Shortcut
{editingShotcut ? 'Update Shortcut' : 'Create New Shortcut'}
</Text>
<TextInput
@ -117,7 +148,7 @@ export function ShotcutForm({ onSubmit }: ShotcutFormProps) {
</Button>
<Button type="submit" size="sm">
Create Shortcut
{editingShotcut ? 'Update Shortcut' : 'Create Shortcut'}
</Button>
</Stack>
</Stack>

View File

@ -3,14 +3,15 @@
import { useState } from 'react'
import { ActionIcon, Badge, Card, Group, Stack, Text, Modal, Button, Flex } from '@mantine/core'
import { IShotcut } from '@renderer/types'
import { IconExternalLink, IconTrash } from '@tabler/icons-react'
import { IconEdit, IconExternalLink, IconTrash } from '@tabler/icons-react'
interface ShotcutListProps {
shotcuts: IShotcut[]
onDelete: (shotcut: IShotcut) => void
onEdit: (shotcut: IShotcut) => void
}
export function ShotcutList({ shotcuts, onDelete }: ShotcutListProps) {
export function ShotcutList({ shotcuts, onDelete, onEdit }: ShotcutListProps) {
const [opened, setOpened] = useState(false)
const [selectedShotcut, setSelectedShotcut] = useState<IShotcut | null>(null)
@ -58,6 +59,14 @@ export function ShotcutList({ shotcuts, onDelete }: ShotcutListProps) {
>
<IconTrash size={16} />
</ActionIcon>
<ActionIcon
variant="outline"
color="blue"
onClick={() => onEdit(shotcut)}
title="Edit shortcut"
>
<IconEdit size={16} />
</ActionIcon>
</Group>
{/* Content */}