update save config
This commit is contained in:
parent
ce4b3baf3a
commit
6b2d980060
|
|
@ -15,15 +15,15 @@ export const defaultShortcuts: IShortcut[] = [
|
||||||
{
|
{
|
||||||
id: uuid(),
|
id: uuid(),
|
||||||
links: [
|
links: [
|
||||||
'https://int.ipsupply.com.au/erptools/001_search-vpn?search=${keyword}',
|
'https://int.ipsupply.com.au/erptools/001_search-vpn?search={keyword}',
|
||||||
'https://www.ebay.com/sch/i.html?_nkw=${keyword}&_sop=15'
|
'https://www.ebay.com/sch/i.html?_nkw={keyword}&_sop=15'
|
||||||
],
|
],
|
||||||
shortcut: 'CommandOrControl+Shift+1'
|
shortcut: 'Control+Shift+1'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: uuid(),
|
id: uuid(),
|
||||||
links: ['https://esearch.danielvu.com?keyword=${keyword}'],
|
links: ['https://esearch.danielvu.com?keyword={keyword}'],
|
||||||
shortcut: 'CommandOrControl+Shift+2'
|
shortcut: 'Control+Shift+2'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -86,7 +86,7 @@ const handleOpenBrowserByLink = (data: IShortcut) => {
|
||||||
const query = encodeURIComponent(text)
|
const query = encodeURIComponent(text)
|
||||||
|
|
||||||
data.links.forEach((link) => {
|
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}`)
|
console.log(`[${new Date().toLocaleTimeString()}] Opening URL: ${url}`)
|
||||||
shell.openExternal(url) // Mở trong browser mặc định
|
shell.openExternal(url) // Mở trong browser mặc định
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import { getConfigFile, saveConfigFile } from './api/config'
|
||||||
function App(): React.JSX.Element {
|
function App(): React.JSX.Element {
|
||||||
const [loading, setLoading] = useState(true)
|
const [loading, setLoading] = useState(true)
|
||||||
const [shotcuts, setShotcuts] = useState<IShotcut[]>([])
|
const [shotcuts, setShotcuts] = useState<IShotcut[]>([])
|
||||||
|
const [editing, setEditing] = useState<IShotcut | null>(null)
|
||||||
|
|
||||||
// Hàm lưu config
|
// Hàm lưu config
|
||||||
const saveConfig = async (newShortcuts: IShotcut[]) => {
|
const saveConfig = async (newShortcuts: IShotcut[]) => {
|
||||||
|
|
@ -30,6 +31,21 @@ function App(): React.JSX.Element {
|
||||||
saveConfig(newShortcuts)
|
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
|
// Gọi IPC để lấy dữ liệu config
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
|
|
@ -67,15 +83,22 @@ function App(): React.JSX.Element {
|
||||||
>
|
>
|
||||||
<Container fluid mt={'lg'}>
|
<Container fluid mt={'lg'}>
|
||||||
<ShotcutForm
|
<ShotcutForm
|
||||||
|
shortcuts={shotcuts}
|
||||||
onSubmit={(newItem) => {
|
onSubmit={(newItem) => {
|
||||||
const updated = [newItem, ...shotcuts]
|
const updated = [newItem, ...shotcuts]
|
||||||
setShotcuts(updated)
|
setShotcuts(updated)
|
||||||
saveConfig(updated)
|
saveConfig(updated)
|
||||||
}}
|
}}
|
||||||
|
editingShotcut={editing || undefined}
|
||||||
|
onUpdate={handleUpdate}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Box py={'lg'}>
|
<Box py={'lg'}>
|
||||||
<ShotcutList shotcuts={shotcuts} onDelete={handleDelete} />
|
<ShotcutList
|
||||||
|
onEdit={handleEdit}
|
||||||
|
shotcuts={shotcuts}
|
||||||
|
onDelete={handleDelete}
|
||||||
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<LoadingOverlay
|
<LoadingOverlay
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import { ActionIcon, Button, Code, Group, Paper, Stack, Text, TextInput } from '
|
||||||
import { useForm, zodResolver } from '@mantine/form'
|
import { useForm, zodResolver } from '@mantine/form'
|
||||||
import { IShotcut } from '@renderer/types'
|
import { IShotcut } from '@renderer/types'
|
||||||
import { IconPlus, IconX } from '@tabler/icons-react'
|
import { IconPlus, IconX } from '@tabler/icons-react'
|
||||||
|
import { useEffect } from 'react'
|
||||||
import { v4 as uuid } from 'uuid'
|
import { v4 as uuid } from 'uuid'
|
||||||
import * as z from 'zod'
|
import * as z from 'zod'
|
||||||
|
|
||||||
|
|
@ -46,11 +47,16 @@ type ShotcutFormValues = z.infer<typeof ShotcutSchema>
|
||||||
|
|
||||||
interface ShotcutFormProps {
|
interface ShotcutFormProps {
|
||||||
onSubmit: (shotcut: IShotcut) => void
|
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>({
|
const form = useForm<ShotcutFormValues>({
|
||||||
initialValues: { shortcut: '', links: [''] },
|
initialValues: editingShotcut
|
||||||
|
? { shortcut: editingShotcut.shortcut, links: editingShotcut.links }
|
||||||
|
: { shortcut: '', links: [''] },
|
||||||
validate: zodResolver(ShotcutSchema)
|
validate: zodResolver(ShotcutSchema)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -58,16 +64,41 @@ export function ShotcutForm({ onSubmit }: ShotcutFormProps) {
|
||||||
const removeLink = (index: number) => form.removeListItem('links', index)
|
const removeLink = (index: number) => form.removeListItem('links', index)
|
||||||
|
|
||||||
const handleSubmit = (values: ShotcutFormValues) => {
|
const handleSubmit = (values: ShotcutFormValues) => {
|
||||||
onSubmit({ ...values, id: uuid() })
|
// Kiểm tra trùng shortcut
|
||||||
form.reset()
|
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 (
|
return (
|
||||||
<Paper shadow="sm" radius="md" p="md" withBorder maw={600} mx="auto">
|
<Paper shadow="sm" radius="md" p="md" withBorder maw={600} mx="auto">
|
||||||
<form onSubmit={form.onSubmit(handleSubmit)}>
|
<form onSubmit={form.onSubmit(handleSubmit)}>
|
||||||
<Stack>
|
<Stack>
|
||||||
<Text size="lg" fw={600}>
|
<Text size="lg" fw={600}>
|
||||||
Create New Shortcut
|
{editingShotcut ? 'Update Shortcut' : 'Create New Shortcut'}
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<TextInput
|
<TextInput
|
||||||
|
|
@ -117,7 +148,7 @@ export function ShotcutForm({ onSubmit }: ShotcutFormProps) {
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Button type="submit" size="sm">
|
<Button type="submit" size="sm">
|
||||||
Create Shortcut
|
{editingShotcut ? 'Update Shortcut' : 'Create Shortcut'}
|
||||||
</Button>
|
</Button>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,15 @@
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { ActionIcon, Badge, Card, Group, Stack, Text, Modal, Button, Flex } from '@mantine/core'
|
import { ActionIcon, Badge, Card, Group, Stack, Text, Modal, Button, Flex } from '@mantine/core'
|
||||||
import { IShotcut } from '@renderer/types'
|
import { IShotcut } from '@renderer/types'
|
||||||
import { IconExternalLink, IconTrash } from '@tabler/icons-react'
|
import { IconEdit, IconExternalLink, IconTrash } from '@tabler/icons-react'
|
||||||
|
|
||||||
interface ShotcutListProps {
|
interface ShotcutListProps {
|
||||||
shotcuts: IShotcut[]
|
shotcuts: IShotcut[]
|
||||||
onDelete: (shotcut: IShotcut) => void
|
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 [opened, setOpened] = useState(false)
|
||||||
const [selectedShotcut, setSelectedShotcut] = useState<IShotcut | null>(null)
|
const [selectedShotcut, setSelectedShotcut] = useState<IShotcut | null>(null)
|
||||||
|
|
||||||
|
|
@ -58,6 +59,14 @@ export function ShotcutList({ shotcuts, onDelete }: ShotcutListProps) {
|
||||||
>
|
>
|
||||||
<IconTrash size={16} />
|
<IconTrash size={16} />
|
||||||
</ActionIcon>
|
</ActionIcon>
|
||||||
|
<ActionIcon
|
||||||
|
variant="outline"
|
||||||
|
color="blue"
|
||||||
|
onClick={() => onEdit(shotcut)}
|
||||||
|
title="Edit shortcut"
|
||||||
|
>
|
||||||
|
<IconEdit size={16} />
|
||||||
|
</ActionIcon>
|
||||||
</Group>
|
</Group>
|
||||||
|
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue