staging #6
			
				
			
		
		
		
	| 
						 | 
					@ -0,0 +1,2 @@
 | 
				
			||||||
 | 
					VITE_BASE_URL = 'http://localhost:4000/api/v1/admin/'
 | 
				
			||||||
 | 
					VITE_SOCKET_URL = 'http://localhost:4000'
 | 
				
			||||||
| 
						 | 
					@ -1,10 +1,10 @@
 | 
				
			||||||
/* eslint-disable @typescript-eslint/no-unused-vars */
 | 
					/* 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 { useForm, zodResolver } from '@mantine/form';
 | 
				
			||||||
import { useDisclosure } from '@mantine/hooks';
 | 
					import { useDisclosure } from '@mantine/hooks';
 | 
				
			||||||
import { IconPlus } from '@tabler/icons-react';
 | 
					import { IconPlus } from '@tabler/icons-react';
 | 
				
			||||||
import _ from 'lodash';
 | 
					import _ from 'lodash';
 | 
				
			||||||
import { useEffect, useRef } from 'react';
 | 
					import { useEffect, useRef, useState } from 'react';
 | 
				
			||||||
import { z } from 'zod';
 | 
					import { z } from 'zod';
 | 
				
			||||||
import { createAdmin, updateAdmin } from '../../apis/admin';
 | 
					import { createAdmin, updateAdmin } from '../../apis/admin';
 | 
				
			||||||
import { useConfirmStore } from '../../lib/zustand/use-confirm';
 | 
					import { useConfirmStore } from '../../lib/zustand/use-confirm';
 | 
				
			||||||
| 
						 | 
					@ -40,6 +40,8 @@ export default function AdminModal({ data, onUpdated, ...props }: IAdminModelPro
 | 
				
			||||||
        validate: zodResolver(data ? updateSchema : createSchema),
 | 
					        validate: zodResolver(data ? updateSchema : createSchema),
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const [loading, setLoading] = useState(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const [opened, { open, close }] = useDisclosure(false);
 | 
					    const [opened, { open, close }] = useDisclosure(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const { deletePermission, setPermissions, permissions, basePermission } = usePermissionStore();
 | 
					    const { deletePermission, setPermissions, permissions, basePermission } = usePermissionStore();
 | 
				
			||||||
| 
						 | 
					@ -54,7 +56,9 @@ export default function AdminModal({ data, onUpdated, ...props }: IAdminModelPro
 | 
				
			||||||
                title: 'Update ?',
 | 
					                title: 'Update ?',
 | 
				
			||||||
                message: `This account will be update`,
 | 
					                message: `This account will be update`,
 | 
				
			||||||
                handleOk: async () => {
 | 
					                handleOk: async () => {
 | 
				
			||||||
 | 
					                    setLoading(true);
 | 
				
			||||||
                    const result = await updateAdmin(values);
 | 
					                    const result = await updateAdmin(values);
 | 
				
			||||||
 | 
					                    setLoading(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    if (!result) return;
 | 
					                    if (!result) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -72,7 +76,10 @@ export default function AdminModal({ data, onUpdated, ...props }: IAdminModelPro
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            const { confirmPassword, ...newValues } = values;
 | 
					            const { confirmPassword, ...newValues } = values;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            setLoading(true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            const result = await createAdmin(newValues as Omit<IAdmin, 'id' | 'created_at' | 'updated_at' | 'is_system_account'>);
 | 
					            const result = await createAdmin(newValues as Omit<IAdmin, 'id' | 'created_at' | 'updated_at' | 'is_system_account'>);
 | 
				
			||||||
 | 
					            setLoading(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (!result) return;
 | 
					            if (!result) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -110,6 +117,7 @@ export default function AdminModal({ data, onUpdated, ...props }: IAdminModelPro
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <Modal
 | 
					        <Modal
 | 
				
			||||||
 | 
					            className="relative"
 | 
				
			||||||
            classNames={{
 | 
					            classNames={{
 | 
				
			||||||
                header: '!flex !item-center !justify-center w-full',
 | 
					                header: '!flex !item-center !justify-center w-full',
 | 
				
			||||||
            }}
 | 
					            }}
 | 
				
			||||||
| 
						 | 
					@ -160,6 +168,8 @@ export default function AdminModal({ data, onUpdated, ...props }: IAdminModelPro
 | 
				
			||||||
            </form>
 | 
					            </form>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <PermissionDrawer opened={opened} onClose={close} />
 | 
					            <PermissionDrawer opened={opened} onClose={close} />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <LoadingOverlay visible={loading} zIndex={1000} overlayProps={{ blur: 2 }} />
 | 
				
			||||||
        </Modal>
 | 
					        </Modal>
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,7 @@
 | 
				
			||||||
/* eslint-disable @typescript-eslint/no-unused-vars */
 | 
					/* 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 { useForm, zodResolver } from '@mantine/form';
 | 
				
			||||||
import { useEffect } from 'react';
 | 
					import { useEffect, useState } from 'react';
 | 
				
			||||||
import { z } from 'zod';
 | 
					import { z } from 'zod';
 | 
				
			||||||
import { grantNewPasswordAdmin } from '../../apis/admin';
 | 
					import { grantNewPasswordAdmin } from '../../apis/admin';
 | 
				
			||||||
import { useConfirmStore } from '../../lib/zustand/use-confirm';
 | 
					import { useConfirmStore } from '../../lib/zustand/use-confirm';
 | 
				
			||||||
| 
						 | 
					@ -26,6 +26,8 @@ export default function GrantNewPasswordModal({ data, onUpdated, ...props }: IAd
 | 
				
			||||||
        validate: zodResolver(schema),
 | 
					        validate: zodResolver(schema),
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const [loading, setLoading] = useState(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const { setConfirm } = useConfirmStore();
 | 
					    const { setConfirm } = useConfirmStore();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const handleSubmit = async (values: typeof form.values) => {
 | 
					    const handleSubmit = async (values: typeof form.values) => {
 | 
				
			||||||
| 
						 | 
					@ -34,10 +36,12 @@ export default function GrantNewPasswordModal({ data, onUpdated, ...props }: IAd
 | 
				
			||||||
                title: 'Update ?',
 | 
					                title: 'Update ?',
 | 
				
			||||||
                message: `This account will be update`,
 | 
					                message: `This account will be update`,
 | 
				
			||||||
                handleOk: async () => {
 | 
					                handleOk: async () => {
 | 
				
			||||||
 | 
					                    setLoading(true);
 | 
				
			||||||
                    const result = await grantNewPasswordAdmin({
 | 
					                    const result = await grantNewPasswordAdmin({
 | 
				
			||||||
                        id: data.id,
 | 
					                        id: data.id,
 | 
				
			||||||
                        password: values.password,
 | 
					                        password: values.password,
 | 
				
			||||||
                    });
 | 
					                    });
 | 
				
			||||||
 | 
					                    setLoading(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    if (!result) return;
 | 
					                    if (!result) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -73,6 +77,7 @@ export default function GrantNewPasswordModal({ data, onUpdated, ...props }: IAd
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <Modal
 | 
					        <Modal
 | 
				
			||||||
 | 
					            className="relative"
 | 
				
			||||||
            classNames={{
 | 
					            classNames={{
 | 
				
			||||||
                header: '!flex !item-center !justify-center w-full',
 | 
					                header: '!flex !item-center !justify-center w-full',
 | 
				
			||||||
            }}
 | 
					            }}
 | 
				
			||||||
| 
						 | 
					@ -89,6 +94,8 @@ export default function GrantNewPasswordModal({ data, onUpdated, ...props }: IAd
 | 
				
			||||||
                    {'Grant'}
 | 
					                    {'Grant'}
 | 
				
			||||||
                </Button>
 | 
					                </Button>
 | 
				
			||||||
            </form>
 | 
					            </form>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <LoadingOverlay visible={loading} zIndex={1000} overlayProps={{ blur: 2 }} />
 | 
				
			||||||
        </Modal>
 | 
					        </Modal>
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,8 +1,8 @@
 | 
				
			||||||
/* eslint-disable @typescript-eslint/no-unused-vars */
 | 
					/* 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 { useForm, zodResolver } from '@mantine/form';
 | 
				
			||||||
import _ from 'lodash';
 | 
					import _ from 'lodash';
 | 
				
			||||||
import { useEffect, useRef } from 'react';
 | 
					import { useEffect, useRef, useState } from 'react';
 | 
				
			||||||
import { z } from 'zod';
 | 
					import { z } from 'zod';
 | 
				
			||||||
import { createBid, updateBid } from '../../apis/bid';
 | 
					import { createBid, updateBid } from '../../apis/bid';
 | 
				
			||||||
import { useConfirmStore } from '../../lib/zustand/use-confirm';
 | 
					import { useConfirmStore } from '../../lib/zustand/use-confirm';
 | 
				
			||||||
| 
						 | 
					@ -28,13 +28,17 @@ export default function BidModal({ data, onUpdated, ...props }: IBidModelProps)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const { setConfirm } = useConfirmStore();
 | 
					    const { setConfirm } = useConfirmStore();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const [loading, setLoading] = useState(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const handleSubmit = async (values: typeof form.values) => {
 | 
					    const handleSubmit = async (values: typeof form.values) => {
 | 
				
			||||||
        if (data) {
 | 
					        if (data) {
 | 
				
			||||||
            setConfirm({
 | 
					            setConfirm({
 | 
				
			||||||
                title: 'Update ?',
 | 
					                title: 'Update ?',
 | 
				
			||||||
                message: `This product will be update`,
 | 
					                message: `This product will be update`,
 | 
				
			||||||
                handleOk: async () => {
 | 
					                handleOk: async () => {
 | 
				
			||||||
 | 
					                    setLoading(true);
 | 
				
			||||||
                    const result = await updateBid(values);
 | 
					                    const result = await updateBid(values);
 | 
				
			||||||
 | 
					                    setLoading(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    if (!result) return;
 | 
					                    if (!result) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -52,8 +56,11 @@ export default function BidModal({ data, onUpdated, ...props }: IBidModelProps)
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            const { url, max_price, plus_price } = values;
 | 
					            const { url, max_price, plus_price } = values;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            setLoading(true);
 | 
				
			||||||
            const result = await createBid({ url, max_price, plus_price } as IBid);
 | 
					            const result = await createBid({ url, max_price, plus_price } as IBid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            setLoading(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (!result) return;
 | 
					            if (!result) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            props.onClose();
 | 
					            props.onClose();
 | 
				
			||||||
| 
						 | 
					@ -83,6 +90,7 @@ export default function BidModal({ data, onUpdated, ...props }: IBidModelProps)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <Modal
 | 
					        <Modal
 | 
				
			||||||
 | 
					            className="relative"
 | 
				
			||||||
            classNames={{
 | 
					            classNames={{
 | 
				
			||||||
                header: '!flex !item-center !justify-center w-full',
 | 
					                header: '!flex !item-center !justify-center w-full',
 | 
				
			||||||
            }}
 | 
					            }}
 | 
				
			||||||
| 
						 | 
					@ -102,6 +110,8 @@ export default function BidModal({ data, onUpdated, ...props }: IBidModelProps)
 | 
				
			||||||
                    {data ? 'Update' : 'Create'}
 | 
					                    {data ? 'Update' : 'Create'}
 | 
				
			||||||
                </Button>
 | 
					                </Button>
 | 
				
			||||||
            </form>
 | 
					            </form>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <LoadingOverlay visible={loading} zIndex={1000} overlayProps={{ blur: 2 }} />
 | 
				
			||||||
        </Modal>
 | 
					        </Modal>
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,5 @@
 | 
				
			||||||
/* eslint-disable @typescript-eslint/no-unused-vars */
 | 
					/* 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 { useCallback, useEffect, useMemo, useState } from 'react';
 | 
				
			||||||
import { getDetailBidHistories } from '../../apis/bid-histories';
 | 
					import { getDetailBidHistories } from '../../apis/bid-histories';
 | 
				
			||||||
import { extractNumber } from '../../lib/table/ultils';
 | 
					import { extractNumber } from '../../lib/table/ultils';
 | 
				
			||||||
| 
						 | 
					@ -14,6 +14,8 @@ export interface IShowHistoriesBidGraysApiModalProps extends ModalProps {
 | 
				
			||||||
export default function ShowHistoriesBidGraysApiModal({ data, onUpdated, ...props }: IShowHistoriesBidGraysApiModalProps) {
 | 
					export default function ShowHistoriesBidGraysApiModal({ data, onUpdated, ...props }: IShowHistoriesBidGraysApiModalProps) {
 | 
				
			||||||
    const [histories, setHistories] = useState<Record<string, string>[]>([]);
 | 
					    const [histories, setHistories] = useState<Record<string, string>[]>([]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const [loading, setLoading] = useState(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const rows = useMemo(() => {
 | 
					    const rows = useMemo(() => {
 | 
				
			||||||
        return histories.map((element) => (
 | 
					        return histories.map((element) => (
 | 
				
			||||||
            <Table.Tr key={element.LotId}>
 | 
					            <Table.Tr key={element.LotId}>
 | 
				
			||||||
| 
						 | 
					@ -33,7 +35,9 @@ export default function ShowHistoriesBidGraysApiModal({ data, onUpdated, ...prop
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        setLoading(true);
 | 
				
			||||||
        const response = await getDetailBidHistories(data?.lot_id);
 | 
					        const response = await getDetailBidHistories(data?.lot_id);
 | 
				
			||||||
 | 
					        setLoading(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (response.data && response.data) {
 | 
					        if (response.data && response.data) {
 | 
				
			||||||
            setHistories(response.data);
 | 
					            setHistories(response.data);
 | 
				
			||||||
| 
						 | 
					@ -45,7 +49,7 @@ export default function ShowHistoriesBidGraysApiModal({ data, onUpdated, ...prop
 | 
				
			||||||
    }, [handleCallApi]);
 | 
					    }, [handleCallApi]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    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 striped highlightOnHover withTableBorder withColumnBorders>
 | 
				
			||||||
                <Table.Thead>
 | 
					                <Table.Thead>
 | 
				
			||||||
                    <Table.Tr>
 | 
					                    <Table.Tr>
 | 
				
			||||||
| 
						 | 
					@ -68,6 +72,8 @@ export default function ShowHistoriesBidGraysApiModal({ data, onUpdated, ...prop
 | 
				
			||||||
                    )}
 | 
					                    )}
 | 
				
			||||||
                </Table.Tbody>
 | 
					                </Table.Tbody>
 | 
				
			||||||
            </Table>
 | 
					            </Table>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <LoadingOverlay visible={loading} zIndex={1000} overlayProps={{ blur: 2 }} />
 | 
				
			||||||
        </Modal>
 | 
					        </Modal>
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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 { useForm, zodResolver } from '@mantine/form';
 | 
				
			||||||
import { useDisclosure } from '@mantine/hooks';
 | 
					import { useDisclosure } from '@mantine/hooks';
 | 
				
			||||||
import { IconLogout, IconSettings, IconUser } from '@tabler/icons-react';
 | 
					import { IconLogout, IconSettings, IconUser } from '@tabler/icons-react';
 | 
				
			||||||
| 
						 | 
					@ -7,6 +7,7 @@ import { z } from 'zod';
 | 
				
			||||||
import { changePassword, logout } from '../apis/auth';
 | 
					import { changePassword, logout } from '../apis/auth';
 | 
				
			||||||
import { useConfirmStore } from '../lib/zustand/use-confirm';
 | 
					import { useConfirmStore } from '../lib/zustand/use-confirm';
 | 
				
			||||||
import Links from '../system/links';
 | 
					import Links from '../system/links';
 | 
				
			||||||
 | 
					import { useState } from 'react';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const schema = z
 | 
					const schema = z
 | 
				
			||||||
    .object({
 | 
					    .object({
 | 
				
			||||||
| 
						 | 
					@ -24,6 +25,8 @@ export default function UserMenu() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const { setConfirm } = useConfirmStore();
 | 
					    const { setConfirm } = useConfirmStore();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const [loading, setLoading] = useState(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const navigate = useNavigate();
 | 
					    const navigate = useNavigate();
 | 
				
			||||||
    const form = useForm({
 | 
					    const form = useForm({
 | 
				
			||||||
        initialValues: {
 | 
					        initialValues: {
 | 
				
			||||||
| 
						 | 
					@ -59,11 +62,14 @@ export default function UserMenu() {
 | 
				
			||||||
            message: 'This account will change password !',
 | 
					            message: 'This account will change password !',
 | 
				
			||||||
            okButton: { value: 'Sure' },
 | 
					            okButton: { value: 'Sure' },
 | 
				
			||||||
            handleOk: async () => {
 | 
					            handleOk: async () => {
 | 
				
			||||||
 | 
					                setLoading(true);
 | 
				
			||||||
                const data = await changePassword({
 | 
					                const data = await changePassword({
 | 
				
			||||||
                    newPassword: values.newPassword,
 | 
					                    newPassword: values.newPassword,
 | 
				
			||||||
                    password: values.currentPassword,
 | 
					                    password: values.currentPassword,
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                setLoading(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if (data && data.data) {
 | 
					                if (data && data.data) {
 | 
				
			||||||
                    navigate(Links.LOGIN);
 | 
					                    navigate(Links.LOGIN);
 | 
				
			||||||
                    close();
 | 
					                    close();
 | 
				
			||||||
| 
						 | 
					@ -95,7 +101,7 @@ export default function UserMenu() {
 | 
				
			||||||
                </Menu.Dropdown>
 | 
					                </Menu.Dropdown>
 | 
				
			||||||
            </Menu>
 | 
					            </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">
 | 
					                <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="Current password" {...form.getInputProps('currentPassword')} />
 | 
				
			||||||
                    <PasswordInput size="sm" label="New password" {...form.getInputProps('newPassword')} />
 | 
					                    <PasswordInput size="sm" label="New password" {...form.getInputProps('newPassword')} />
 | 
				
			||||||
| 
						 | 
					@ -104,6 +110,8 @@ export default function UserMenu() {
 | 
				
			||||||
                        Change
 | 
					                        Change
 | 
				
			||||||
                    </Button>
 | 
					                    </Button>
 | 
				
			||||||
                </form>
 | 
					                </form>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                <LoadingOverlay visible={loading} zIndex={1000} overlayProps={{ blur: 2 }} />
 | 
				
			||||||
            </Modal>
 | 
					            </Modal>
 | 
				
			||||||
        </>
 | 
					        </>
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,8 +1,8 @@
 | 
				
			||||||
/* eslint-disable @typescript-eslint/no-unused-vars */
 | 
					/* 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 { useForm, zodResolver } from '@mantine/form';
 | 
				
			||||||
import _ from 'lodash';
 | 
					import _ from 'lodash';
 | 
				
			||||||
import { useEffect, useRef } from 'react';
 | 
					import { useEffect, useRef, useState } from 'react';
 | 
				
			||||||
import { z } from 'zod';
 | 
					import { z } from 'zod';
 | 
				
			||||||
import { updateWebBid } from '../../apis/web-bid';
 | 
					import { updateWebBid } from '../../apis/web-bid';
 | 
				
			||||||
import { useConfirmStore } from '../../lib/zustand/use-confirm';
 | 
					import { useConfirmStore } from '../../lib/zustand/use-confirm';
 | 
				
			||||||
| 
						 | 
					@ -22,6 +22,8 @@ export default function WebAccountModal({ data, onUpdated, ...props }: IWebBidMo
 | 
				
			||||||
        validate: zodResolver(schema),
 | 
					        validate: zodResolver(schema),
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const [loading, setLoading] = useState(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const prevData = useRef<IWebBid | null>(data);
 | 
					    const prevData = useRef<IWebBid | null>(data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const { setConfirm } = useConfirmStore();
 | 
					    const { setConfirm } = useConfirmStore();
 | 
				
			||||||
| 
						 | 
					@ -32,7 +34,9 @@ export default function WebAccountModal({ data, onUpdated, ...props }: IWebBidMo
 | 
				
			||||||
                title: 'Update ?',
 | 
					                title: 'Update ?',
 | 
				
			||||||
                message: `This account will be update`,
 | 
					                message: `This account will be update`,
 | 
				
			||||||
                handleOk: async () => {
 | 
					                handleOk: async () => {
 | 
				
			||||||
 | 
					                    setLoading(true);
 | 
				
			||||||
                    const result = await updateWebBid(values);
 | 
					                    const result = await updateWebBid(values);
 | 
				
			||||||
 | 
					                    setLoading(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    if (!result) return;
 | 
					                    if (!result) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -48,7 +52,9 @@ export default function WebAccountModal({ data, onUpdated, ...props }: IWebBidMo
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
 | 
					            setLoading(true);
 | 
				
			||||||
            const result = await updateWebBid(values);
 | 
					            const result = await updateWebBid(values);
 | 
				
			||||||
 | 
					            setLoading(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (!result) return;
 | 
					            if (!result) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -79,6 +85,7 @@ export default function WebAccountModal({ data, onUpdated, ...props }: IWebBidMo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <Modal
 | 
					        <Modal
 | 
				
			||||||
 | 
					            className="relative"
 | 
				
			||||||
            classNames={{
 | 
					            classNames={{
 | 
				
			||||||
                header: '!flex !item-center !justify-center w-full',
 | 
					                header: '!flex !item-center !justify-center w-full',
 | 
				
			||||||
            }}
 | 
					            }}
 | 
				
			||||||
| 
						 | 
					@ -95,6 +102,8 @@ export default function WebAccountModal({ data, onUpdated, ...props }: IWebBidMo
 | 
				
			||||||
                    {data ? 'Update' : 'Create'}
 | 
					                    {data ? 'Update' : 'Create'}
 | 
				
			||||||
                </Button>
 | 
					                </Button>
 | 
				
			||||||
            </form>
 | 
					            </form>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <LoadingOverlay visible={loading} zIndex={1000} overlayProps={{ blur: 2 }} />
 | 
				
			||||||
        </Modal>
 | 
					        </Modal>
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,8 +1,8 @@
 | 
				
			||||||
/* eslint-disable @typescript-eslint/no-unused-vars */
 | 
					/* 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 { useForm, zodResolver } from '@mantine/form';
 | 
				
			||||||
import _ from 'lodash';
 | 
					import _ from 'lodash';
 | 
				
			||||||
import { useEffect, useRef } from 'react';
 | 
					import { useEffect, useRef, useState } from 'react';
 | 
				
			||||||
import { z } from 'zod';
 | 
					import { z } from 'zod';
 | 
				
			||||||
import { createWebBid, updateWebBid } from '../../apis/web-bid';
 | 
					import { createWebBid, updateWebBid } from '../../apis/web-bid';
 | 
				
			||||||
import { useConfirmStore } from '../../lib/zustand/use-confirm';
 | 
					import { useConfirmStore } from '../../lib/zustand/use-confirm';
 | 
				
			||||||
| 
						 | 
					@ -22,6 +22,8 @@ export default function WebBidModal({ data, onUpdated, ...props }: IWebBidModelP
 | 
				
			||||||
        validate: zodResolver(z.object(schema)),
 | 
					        validate: zodResolver(z.object(schema)),
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const [loading, setLoading] = useState(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const prevData = useRef<IWebBid | null>(data);
 | 
					    const prevData = useRef<IWebBid | null>(data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const { setConfirm } = useConfirmStore();
 | 
					    const { setConfirm } = useConfirmStore();
 | 
				
			||||||
| 
						 | 
					@ -32,7 +34,9 @@ export default function WebBidModal({ data, onUpdated, ...props }: IWebBidModelP
 | 
				
			||||||
                title: 'Update ?',
 | 
					                title: 'Update ?',
 | 
				
			||||||
                message: `This web will be update`,
 | 
					                message: `This web will be update`,
 | 
				
			||||||
                handleOk: async () => {
 | 
					                handleOk: async () => {
 | 
				
			||||||
 | 
					                    setLoading(true);
 | 
				
			||||||
                    const result = await updateWebBid(values);
 | 
					                    const result = await updateWebBid(values);
 | 
				
			||||||
 | 
					                    setLoading(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    if (!result) return;
 | 
					                    if (!result) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -50,7 +54,9 @@ export default function WebBidModal({ data, onUpdated, ...props }: IWebBidModelP
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            const { url, origin_url } = values;
 | 
					            const { url, origin_url } = values;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            setLoading(true);
 | 
				
			||||||
            const result = await createWebBid({ url, origin_url } as IWebBid);
 | 
					            const result = await createWebBid({ url, origin_url } as IWebBid);
 | 
				
			||||||
 | 
					            setLoading(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (!result) return;
 | 
					            if (!result) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -88,6 +94,7 @@ export default function WebBidModal({ data, onUpdated, ...props }: IWebBidModelP
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return (
 | 
					    return (
 | 
				
			||||||
        <Modal
 | 
					        <Modal
 | 
				
			||||||
 | 
					            className="relative"
 | 
				
			||||||
            classNames={{
 | 
					            classNames={{
 | 
				
			||||||
                header: '!flex !item-center !justify-center w-full',
 | 
					                header: '!flex !item-center !justify-center w-full',
 | 
				
			||||||
            }}
 | 
					            }}
 | 
				
			||||||
| 
						 | 
					@ -104,6 +111,8 @@ export default function WebBidModal({ data, onUpdated, ...props }: IWebBidModelP
 | 
				
			||||||
                    {data ? 'Update' : 'Create'}
 | 
					                    {data ? 'Update' : 'Create'}
 | 
				
			||||||
                </Button>
 | 
					                </Button>
 | 
				
			||||||
            </form>
 | 
					            </form>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <LoadingOverlay visible={loading} zIndex={1000} overlayProps={{ blur: 2 }} />
 | 
				
			||||||
        </Modal>
 | 
					        </Modal>
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,30 @@
 | 
				
			||||||
 | 
					DB_HOST=127.0.0.1
 | 
				
			||||||
 | 
					# DB_HOST=127.0.0.1
 | 
				
			||||||
 | 
					DB_USERNAME=root
 | 
				
			||||||
 | 
					DB_PASSWORD=123
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ENVIRONMENT='dev'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DB_PORT=3306
 | 
				
			||||||
 | 
					DB_NAME=auto-bids
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PORT = 4000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					APP_PATH = 'http://localhost:4000'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CORS = "http://localhost:5173, http://localhost:3000"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SECRET_KEY = "kgmwljwekqiq25232mdmsgnekwhlwekmglkwjqjwqw"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# DEV GROUP 
 | 
				
			||||||
 | 
					TELEGRAM_BOT_TOKEN = "7963294152:AAE8b9AbsyLYzpeJbUMIcelVWlCBN5mLJ2o"
 | 
				
			||||||
 | 
					CHAT_ID = "-1002593407119"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Bid histories GROUP
 | 
				
			||||||
 | 
					# TELEGRAM_BOT_TOKEN = "7533631751:AAEfE7Ei015U1sSsYPSAYwbYXWFl5D7y_18"
 | 
				
			||||||
 | 
					# CHAT_ID = "-1002535794248"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,6 +2,11 @@ import { MigrationInterface, QueryRunner } from 'typeorm';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export class CreateAdminTable1742778498009 implements MigrationInterface {
 | 
					export class CreateAdminTable1742778498009 implements MigrationInterface {
 | 
				
			||||||
  public async up(queryRunner: QueryRunner): Promise<void> {
 | 
					  public async up(queryRunner: QueryRunner): Promise<void> {
 | 
				
			||||||
 | 
					    // {
 | 
				
			||||||
 | 
					    //     'username': 'admin',
 | 
				
			||||||
 | 
					    //     'password': 'Admin@123'
 | 
				
			||||||
 | 
					    // }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    await queryRunner.query(`
 | 
					    await queryRunner.query(`
 | 
				
			||||||
            INSERT INTO admins (email, username, password, is_system_account) VALUES 
 | 
					            INSERT INTO admins (email, username, password, is_system_account) VALUES 
 | 
				
			||||||
            ('admin@gmail.com', 'admin', '$2b$10$eF7K4Msw32e5ZC2cU78KgOqxMJygQcPDt5xXZP29inBBIV9KEsoyO', 1);
 | 
					            ('admin@gmail.com', 'admin', '$2b$10$eF7K4Msw32e5ZC2cU78KgOqxMJygQcPDt5xXZP29inBBIV9KEsoyO', 1);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -24,6 +24,9 @@ export default class Admin extends Timestamp {
 | 
				
			||||||
  @Column({ type: 'boolean', default: false })
 | 
					  @Column({ type: 'boolean', default: false })
 | 
				
			||||||
  is_system_account: boolean;
 | 
					  is_system_account: boolean;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @ManyToMany(() => Permission, (permission) => permission.admins)
 | 
					  @ManyToMany(() => Permission, (permission) => permission.admins, {
 | 
				
			||||||
 | 
					    cascade: true,
 | 
				
			||||||
 | 
					    onDelete: 'CASCADE',
 | 
				
			||||||
 | 
					  })
 | 
				
			||||||
  permissions: Permission[];
 | 
					  permissions: Permission[];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,3 @@
 | 
				
			||||||
 | 
					ENVIRONMENT = 'prod'
 | 
				
			||||||
 | 
					SOCKET_URL = 'http://localhost:4000'
 | 
				
			||||||
 | 
					BASE_URL = 'http://localhost:4000/api/v1/'
 | 
				
			||||||
| 
						 | 
					@ -40,9 +40,6 @@ lerna-debug.log*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# dotenv environment variable files
 | 
					# dotenv environment variable files
 | 
				
			||||||
.env
 | 
					.env
 | 
				
			||||||
.env.development.local
 | 
					 | 
				
			||||||
.env.test.local
 | 
					 | 
				
			||||||
.env.production.local
 | 
					 | 
				
			||||||
.env.local
 | 
					.env.local
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# temp directory
 | 
					# temp directory
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,19 +5,32 @@ import StealthPlugin from 'puppeteer-extra-plugin-stealth';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
puppeteer.use(StealthPlugin());
 | 
					puppeteer.use(StealthPlugin());
 | 
				
			||||||
const browser = await puppeteer.launch({
 | 
					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
 | 
					    // userDataDir: CONSTANTS.PROFILE_PATH, // Thư mục lưu profile
 | 
				
			||||||
    timeout: 60000,
 | 
					    timeout: 60000,
 | 
				
			||||||
    args: [
 | 
					    args: [
 | 
				
			||||||
        '--no-sandbox',
 | 
					        '--no-sandbox',
 | 
				
			||||||
        '--disable-setuid-sandbox',
 | 
					        '--disable-setuid-sandbox',
 | 
				
			||||||
        '--disable-backgrounding-occluded-windows',
 | 
					        '--disable-dev-shm-usage',
 | 
				
			||||||
        '--disable-renderer-backgrounding',
 | 
					        '--disable-gpu',
 | 
				
			||||||
        '--disable-ipc-flooding-protection',
 | 
					        '--disable-software-rasterizer',
 | 
				
			||||||
        '--disable-features=CalculateNativeWinOcclusion,AudioServiceOutOfProcess',
 | 
					        '--disable-background-networking',
 | 
				
			||||||
        '--disable-background-timer-throttling',
 | 
					        '--disable-sync',
 | 
				
			||||||
 | 
					        '--mute-audio',
 | 
				
			||||||
 | 
					        '--no-first-run',
 | 
				
			||||||
 | 
					        '--no-default-browser-check',
 | 
				
			||||||
        '--ignore-certificate-errors',
 | 
					        '--ignore-certificate-errors',
 | 
				
			||||||
        '--start-maximized',
 | 
					        '--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
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue