update browser args

This commit is contained in:
nkhangg 2025-03-25 09:05:13 +07:00
parent 7445cd5032
commit 614b8ca77c
10 changed files with 101 additions and 21 deletions

View File

@ -1,10 +1,10 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import { Badge, Box, Button, Modal, ModalProps, PasswordInput, Text, TextInput, Tooltip } from '@mantine/core';
import { Badge, Box, Button, LoadingOverlay, Modal, ModalProps, PasswordInput, Text, TextInput, Tooltip } from '@mantine/core';
import { useForm, zodResolver } from '@mantine/form';
import { useDisclosure } from '@mantine/hooks';
import { IconPlus } from '@tabler/icons-react';
import _ from 'lodash';
import { useEffect, useRef } from 'react';
import { useEffect, useRef, useState } from 'react';
import { z } from 'zod';
import { createAdmin, updateAdmin } from '../../apis/admin';
import { useConfirmStore } from '../../lib/zustand/use-confirm';
@ -40,6 +40,8 @@ export default function AdminModal({ data, onUpdated, ...props }: IAdminModelPro
validate: zodResolver(data ? updateSchema : createSchema),
});
const [loading, setLoading] = useState(false);
const [opened, { open, close }] = useDisclosure(false);
const { deletePermission, setPermissions, permissions, basePermission } = usePermissionStore();
@ -54,7 +56,9 @@ export default function AdminModal({ data, onUpdated, ...props }: IAdminModelPro
title: 'Update ?',
message: `This account will be update`,
handleOk: async () => {
setLoading(true);
const result = await updateAdmin(values);
setLoading(false);
if (!result) return;
@ -72,7 +76,10 @@ export default function AdminModal({ data, onUpdated, ...props }: IAdminModelPro
} else {
const { confirmPassword, ...newValues } = values;
setLoading(true);
const result = await createAdmin(newValues as Omit<IAdmin, 'id' | 'created_at' | 'updated_at' | 'is_system_account'>);
setLoading(false);
if (!result) return;
@ -110,6 +117,7 @@ export default function AdminModal({ data, onUpdated, ...props }: IAdminModelPro
return (
<Modal
className="relative"
classNames={{
header: '!flex !item-center !justify-center w-full',
}}
@ -160,6 +168,8 @@ export default function AdminModal({ data, onUpdated, ...props }: IAdminModelPro
</form>
<PermissionDrawer opened={opened} onClose={close} />
<LoadingOverlay visible={loading} zIndex={1000} overlayProps={{ blur: 2 }} />
</Modal>
);
}

View File

@ -1,7 +1,7 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import { Button, Modal, ModalProps, PasswordInput } from '@mantine/core';
import { Button, LoadingOverlay, Modal, ModalProps, PasswordInput } from '@mantine/core';
import { useForm, zodResolver } from '@mantine/form';
import { useEffect } from 'react';
import { useEffect, useState } from 'react';
import { z } from 'zod';
import { grantNewPasswordAdmin } from '../../apis/admin';
import { useConfirmStore } from '../../lib/zustand/use-confirm';
@ -26,6 +26,8 @@ export default function GrantNewPasswordModal({ data, onUpdated, ...props }: IAd
validate: zodResolver(schema),
});
const [loading, setLoading] = useState(false);
const { setConfirm } = useConfirmStore();
const handleSubmit = async (values: typeof form.values) => {
@ -34,10 +36,12 @@ export default function GrantNewPasswordModal({ data, onUpdated, ...props }: IAd
title: 'Update ?',
message: `This account will be update`,
handleOk: async () => {
setLoading(true);
const result = await grantNewPasswordAdmin({
id: data.id,
password: values.password,
});
setLoading(false);
if (!result) return;
@ -73,6 +77,7 @@ export default function GrantNewPasswordModal({ data, onUpdated, ...props }: IAd
return (
<Modal
className="relative"
classNames={{
header: '!flex !item-center !justify-center w-full',
}}
@ -89,6 +94,8 @@ export default function GrantNewPasswordModal({ data, onUpdated, ...props }: IAd
{'Grant'}
</Button>
</form>
<LoadingOverlay visible={loading} zIndex={1000} overlayProps={{ blur: 2 }} />
</Modal>
);
}

View File

@ -1,8 +1,8 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import { Button, Modal, ModalProps, NumberInput, TextInput } from '@mantine/core';
import { Button, LoadingOverlay, Modal, ModalProps, NumberInput, TextInput } from '@mantine/core';
import { useForm, zodResolver } from '@mantine/form';
import _ from 'lodash';
import { useEffect, useRef } from 'react';
import { useEffect, useRef, useState } from 'react';
import { z } from 'zod';
import { createBid, updateBid } from '../../apis/bid';
import { useConfirmStore } from '../../lib/zustand/use-confirm';
@ -28,13 +28,17 @@ export default function BidModal({ data, onUpdated, ...props }: IBidModelProps)
const { setConfirm } = useConfirmStore();
const [loading, setLoading] = useState(false);
const handleSubmit = async (values: typeof form.values) => {
if (data) {
setConfirm({
title: 'Update ?',
message: `This product will be update`,
handleOk: async () => {
setLoading(true);
const result = await updateBid(values);
setLoading(false);
if (!result) return;
@ -52,8 +56,11 @@ export default function BidModal({ data, onUpdated, ...props }: IBidModelProps)
} else {
const { url, max_price, plus_price } = values;
setLoading(true);
const result = await createBid({ url, max_price, plus_price } as IBid);
setLoading(false);
if (!result) return;
props.onClose();
@ -83,6 +90,7 @@ export default function BidModal({ data, onUpdated, ...props }: IBidModelProps)
return (
<Modal
className="relative"
classNames={{
header: '!flex !item-center !justify-center w-full',
}}
@ -102,6 +110,8 @@ export default function BidModal({ data, onUpdated, ...props }: IBidModelProps)
{data ? 'Update' : 'Create'}
</Button>
</form>
<LoadingOverlay visible={loading} zIndex={1000} overlayProps={{ blur: 2 }} />
</Modal>
);
}

View File

@ -1,5 +1,5 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import { Modal, ModalProps, Table } from '@mantine/core';
import { LoadingOverlay, Modal, ModalProps, Table } from '@mantine/core';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { getDetailBidHistories } from '../../apis/bid-histories';
import { extractNumber } from '../../lib/table/ultils';
@ -14,6 +14,8 @@ export interface IShowHistoriesBidGraysApiModalProps extends ModalProps {
export default function ShowHistoriesBidGraysApiModal({ data, onUpdated, ...props }: IShowHistoriesBidGraysApiModalProps) {
const [histories, setHistories] = useState<Record<string, string>[]>([]);
const [loading, setLoading] = useState(false);
const rows = useMemo(() => {
return histories.map((element) => (
<Table.Tr key={element.LotId}>
@ -33,7 +35,9 @@ export default function ShowHistoriesBidGraysApiModal({ data, onUpdated, ...prop
return;
}
setLoading(true);
const response = await getDetailBidHistories(data?.lot_id);
setLoading(false);
if (response.data && response.data) {
setHistories(response.data);
@ -45,7 +49,7 @@ export default function ShowHistoriesBidGraysApiModal({ data, onUpdated, ...prop
}, [handleCallApi]);
return (
<Modal {...props} size="xl" title={<span className="text-xl font-bold">BIDDING HISTORY</span>} centered>
<Modal className="relative" {...props} size="xl" title={<span className="text-xl font-bold">BIDDING HISTORY</span>} centered>
<Table striped highlightOnHover withTableBorder withColumnBorders>
<Table.Thead>
<Table.Tr>
@ -68,6 +72,8 @@ export default function ShowHistoriesBidGraysApiModal({ data, onUpdated, ...prop
)}
</Table.Tbody>
</Table>
<LoadingOverlay visible={loading} zIndex={1000} overlayProps={{ blur: 2 }} />
</Modal>
);
}

View File

@ -1,4 +1,4 @@
import { Avatar, Button, Menu, Modal, PasswordInput } from '@mantine/core';
import { Avatar, Button, LoadingOverlay, Menu, Modal, PasswordInput } from '@mantine/core';
import { useForm, zodResolver } from '@mantine/form';
import { useDisclosure } from '@mantine/hooks';
import { IconLogout, IconSettings, IconUser } from '@tabler/icons-react';
@ -7,6 +7,7 @@ import { z } from 'zod';
import { changePassword, logout } from '../apis/auth';
import { useConfirmStore } from '../lib/zustand/use-confirm';
import Links from '../system/links';
import { useState } from 'react';
const schema = z
.object({
@ -24,6 +25,8 @@ export default function UserMenu() {
const { setConfirm } = useConfirmStore();
const [loading, setLoading] = useState(false);
const navigate = useNavigate();
const form = useForm({
initialValues: {
@ -59,11 +62,14 @@ export default function UserMenu() {
message: 'This account will change password !',
okButton: { value: 'Sure' },
handleOk: async () => {
setLoading(true);
const data = await changePassword({
newPassword: values.newPassword,
password: values.currentPassword,
});
setLoading(false);
if (data && data.data) {
navigate(Links.LOGIN);
close();
@ -95,7 +101,7 @@ export default function UserMenu() {
</Menu.Dropdown>
</Menu>
<Modal opened={opened} onClose={close} title="Change password" centered>
<Modal className="relative" opened={opened} onClose={close} title="Change password" centered>
<form onSubmit={form.onSubmit(handleSubmit)} className="flex flex-col gap-2.5">
<PasswordInput size="sm" label="Current password" {...form.getInputProps('currentPassword')} />
<PasswordInput size="sm" label="New password" {...form.getInputProps('newPassword')} />
@ -104,6 +110,8 @@ export default function UserMenu() {
Change
</Button>
</form>
<LoadingOverlay visible={loading} zIndex={1000} overlayProps={{ blur: 2 }} />
</Modal>
</>
);

View File

@ -1,8 +1,8 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import { Button, Modal, ModalProps, PasswordInput, TextInput } from '@mantine/core';
import { Button, LoadingOverlay, Modal, ModalProps, PasswordInput, TextInput } from '@mantine/core';
import { useForm, zodResolver } from '@mantine/form';
import _ from 'lodash';
import { useEffect, useRef } from 'react';
import { useEffect, useRef, useState } from 'react';
import { z } from 'zod';
import { updateWebBid } from '../../apis/web-bid';
import { useConfirmStore } from '../../lib/zustand/use-confirm';
@ -22,6 +22,8 @@ export default function WebAccountModal({ data, onUpdated, ...props }: IWebBidMo
validate: zodResolver(schema),
});
const [loading, setLoading] = useState(false);
const prevData = useRef<IWebBid | null>(data);
const { setConfirm } = useConfirmStore();
@ -32,7 +34,9 @@ export default function WebAccountModal({ data, onUpdated, ...props }: IWebBidMo
title: 'Update ?',
message: `This account will be update`,
handleOk: async () => {
setLoading(true);
const result = await updateWebBid(values);
setLoading(false);
if (!result) return;
@ -48,7 +52,9 @@ export default function WebAccountModal({ data, onUpdated, ...props }: IWebBidMo
},
});
} else {
setLoading(true);
const result = await updateWebBid(values);
setLoading(false);
if (!result) return;
@ -79,6 +85,7 @@ export default function WebAccountModal({ data, onUpdated, ...props }: IWebBidMo
return (
<Modal
className="relative"
classNames={{
header: '!flex !item-center !justify-center w-full',
}}
@ -95,6 +102,8 @@ export default function WebAccountModal({ data, onUpdated, ...props }: IWebBidMo
{data ? 'Update' : 'Create'}
</Button>
</form>
<LoadingOverlay visible={loading} zIndex={1000} overlayProps={{ blur: 2 }} />
</Modal>
);
}

View File

@ -1,8 +1,8 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import { Button, Modal, ModalProps, TextInput } from '@mantine/core';
import { Button, LoadingOverlay, Modal, ModalProps, TextInput } from '@mantine/core';
import { useForm, zodResolver } from '@mantine/form';
import _ from 'lodash';
import { useEffect, useRef } from 'react';
import { useEffect, useRef, useState } from 'react';
import { z } from 'zod';
import { createWebBid, updateWebBid } from '../../apis/web-bid';
import { useConfirmStore } from '../../lib/zustand/use-confirm';
@ -22,6 +22,8 @@ export default function WebBidModal({ data, onUpdated, ...props }: IWebBidModelP
validate: zodResolver(z.object(schema)),
});
const [loading, setLoading] = useState(false);
const prevData = useRef<IWebBid | null>(data);
const { setConfirm } = useConfirmStore();
@ -32,7 +34,9 @@ export default function WebBidModal({ data, onUpdated, ...props }: IWebBidModelP
title: 'Update ?',
message: `This web will be update`,
handleOk: async () => {
setLoading(true);
const result = await updateWebBid(values);
setLoading(false);
if (!result) return;
@ -50,7 +54,9 @@ export default function WebBidModal({ data, onUpdated, ...props }: IWebBidModelP
} else {
const { url, origin_url } = values;
setLoading(true);
const result = await createWebBid({ url, origin_url } as IWebBid);
setLoading(false);
if (!result) return;
@ -88,6 +94,7 @@ export default function WebBidModal({ data, onUpdated, ...props }: IWebBidModelP
return (
<Modal
className="relative"
classNames={{
header: '!flex !item-center !justify-center w-full',
}}
@ -104,6 +111,8 @@ export default function WebBidModal({ data, onUpdated, ...props }: IWebBidModelP
{data ? 'Update' : 'Create'}
</Button>
</form>
<LoadingOverlay visible={loading} zIndex={1000} overlayProps={{ blur: 2 }} />
</Modal>
);
}

View File

@ -2,6 +2,11 @@ import { MigrationInterface, QueryRunner } from 'typeorm';
export class CreateAdminTable1742778498009 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
// {
// 'username': 'admin',
// 'password': 'Admin@123'
// }
await queryRunner.query(`
INSERT INTO admins (email, username, password, is_system_account) VALUES
('admin@gmail.com', 'admin', '$2b$10$eF7K4Msw32e5ZC2cU78KgOqxMJygQcPDt5xXZP29inBBIV9KEsoyO', 1);

View File

@ -24,6 +24,9 @@ export default class Admin extends Timestamp {
@Column({ type: 'boolean', default: false })
is_system_account: boolean;
@ManyToMany(() => Permission, (permission) => permission.admins)
@ManyToMany(() => Permission, (permission) => permission.admins, {
cascade: true,
onDelete: 'CASCADE',
})
permissions: Permission[];
}

View File

@ -5,19 +5,32 @@ import StealthPlugin from 'puppeteer-extra-plugin-stealth';
puppeteer.use(StealthPlugin());
const browser = await puppeteer.launch({
headless: process.env.ENVIRONMENT === 'prod' ? true : false,
headless: process.env.ENVIRONMENT === 'prod' ? 'new' : false,
// userDataDir: CONSTANTS.PROFILE_PATH, // Thư mục lưu profile
timeout: 60000,
args: [
'--no-sandbox',
'--disable-setuid-sandbox',
'--disable-backgrounding-occluded-windows',
'--disable-renderer-backgrounding',
'--disable-ipc-flooding-protection',
'--disable-features=CalculateNativeWinOcclusion,AudioServiceOutOfProcess',
'--disable-background-timer-throttling',
'--disable-dev-shm-usage',
'--disable-gpu',
'--disable-software-rasterizer',
'--disable-background-networking',
'--disable-sync',
'--mute-audio',
'--no-first-run',
'--no-default-browser-check',
'--ignore-certificate-errors',
'--start-maximized',
'--disable-site-isolation-trials', // Tắt sandbox riêng cho từng site
'--memory-pressure-off', // Tắt cơ chế bảo vệ bộ nhớ
'--disk-cache-size=0', // Không dùng cache để giảm bộ nhớ
'--enable-low-end-device-mode', // Kích hoạt chế độ tiết kiệm RAM
'--disable-best-effort-tasks', // Tắt tác vụ không quan trọng
'--disable-accelerated-2d-canvas', // Không dùng GPU để vẽ canvas
'--disable-threaded-animation', // Giảm animation chạy trên nhiều thread
'--disable-threaded-scrolling', // Tắt cuộn trang đa luồng
'--disable-logging', // Tắt log debug
'--blink-settings=imagesEnabled=false', // Không tải hình ảnh
],
});