105 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
			
		
		
	
	
			105 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
import { Box, Button, Image, Text } from '@mantine/core';
 | 
						|
import { useDisclosure } from '@mantine/hooks';
 | 
						|
import moment from 'moment';
 | 
						|
import { useEffect, useState } from 'react';
 | 
						|
import { Socket } from 'socket.io-client';
 | 
						|
import { getImagesWorking } from '../../apis/bid';
 | 
						|
import { IBid, IWebBid } from '../../system/type';
 | 
						|
import ShowImageModal from './show-image-modal';
 | 
						|
 | 
						|
export interface IWorkingPageProps {
 | 
						|
    data: (IBid | IWebBid) & { type: string };
 | 
						|
    socket: Socket;
 | 
						|
}
 | 
						|
 | 
						|
export default function WorkingPage({ data, socket }: IWorkingPageProps) {
 | 
						|
    const fallbackSrc = 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRGh5WFH8TOIfRKxUrIgJZoDCs1yvQ4hIcppw&s';
 | 
						|
 | 
						|
    const [opened, { open, close }] = useDisclosure(false);
 | 
						|
 | 
						|
    const [imageSrc, setImageSrc] = useState<string | null>(null);
 | 
						|
 | 
						|
    const [lastUpdate, setLastUpdate] = useState<Date | null>(null);
 | 
						|
 | 
						|
    function isIBid(obj: IBid | IWebBid): obj is IBid {
 | 
						|
        return 'name' in obj;
 | 
						|
    }
 | 
						|
 | 
						|
    const renderUrl = ({ type, id }: (IBid | IWebBid) & { type: string }, name: string) => {
 | 
						|
        return `${import.meta.env.VITE_BASE_URL}bids/status-working/${type.replace('_', '-').toLowerCase()}/${id}/${name}`;
 | 
						|
    };
 | 
						|
 | 
						|
    const extractTime = (filename: string) => {
 | 
						|
        return Number(filename.split('-')[0]) || 0;
 | 
						|
    };
 | 
						|
 | 
						|
    useEffect(() => {
 | 
						|
        const updateImage = ({ type, id, filename }: { type: string; filename: string; id: IBid['id'] }) => {
 | 
						|
            if (type == data.type && id == data.id) {
 | 
						|
                setLastUpdate(new Date(extractTime(filename)));
 | 
						|
                setImageSrc(renderUrl(data, filename));
 | 
						|
            }
 | 
						|
        };
 | 
						|
 | 
						|
        socket.on('working', updateImage);
 | 
						|
 | 
						|
        return () => {
 | 
						|
            socket.off('working', updateImage);
 | 
						|
        };
 | 
						|
        // eslint-disable-next-line react-hooks/exhaustive-deps
 | 
						|
    }, [socket, data.id, data.type]);
 | 
						|
 | 
						|
    useEffect(() => {
 | 
						|
        (async () => {
 | 
						|
            const result = await getImagesWorking(data);
 | 
						|
 | 
						|
            if (!result || !result.data) return;
 | 
						|
 | 
						|
            const filename = result.data[0];
 | 
						|
 | 
						|
            setImageSrc(renderUrl(data, filename));
 | 
						|
            setLastUpdate(new Date(extractTime(filename)));
 | 
						|
        })();
 | 
						|
        // eslint-disable-next-line react-hooks/exhaustive-deps
 | 
						|
    }, []);
 | 
						|
 | 
						|
    return (
 | 
						|
        <>
 | 
						|
            <Box className="rounded-md overflow-hidden relative shadow-lg">
 | 
						|
                <Image
 | 
						|
                    radius="md"
 | 
						|
                    h={300}
 | 
						|
                    style={{
 | 
						|
                        objectFit: 'cover',
 | 
						|
                    }}
 | 
						|
                    fallbackSrc={fallbackSrc}
 | 
						|
                    src={imageSrc}
 | 
						|
                />
 | 
						|
 | 
						|
                <Box className="absolute bg-black/60 inset-0 flex items-center justify-center text-white font-bold flex-col gap-3 p-4 rounded-lg transition duration-300 hover:bg-opacity-70">
 | 
						|
                    <Text className="text-lg tracking-wide text-center font-bold">{isIBid(data) ? data.name : 'Tracking page'}</Text>
 | 
						|
                    {isIBid(data) && <Text className="text-xs tracking-wide">{`Max price: $${data.max_price}`}</Text>}
 | 
						|
                    {isIBid(data) && <Text className="text-xs tracking-wide">{`Current price: $${data.current_price}`}</Text>}
 | 
						|
                    <Text className="text-sm italic opacity-80">{moment(lastUpdate).format('HH:mm:ss DD/MM/YYYY')}</Text>
 | 
						|
                    <Box className="flex items-center gap-4">
 | 
						|
                        <Button size="xs" color="green" onClick={open} className="bg-white text-black px-4 py-2 rounded-md shadow-md hover:bg-gray-200 transition">
 | 
						|
                            Show
 | 
						|
                        </Button>
 | 
						|
                        <Button
 | 
						|
                            target="_blank"
 | 
						|
                            component="a"
 | 
						|
                            size="xs"
 | 
						|
                            href={data.url || '/'}
 | 
						|
                            className="bg-white text-black px-4 py-2 rounded-md shadow-md hover:bg-gray-200 transition"
 | 
						|
                        >
 | 
						|
                            Link
 | 
						|
                        </Button>
 | 
						|
                    </Box>
 | 
						|
                </Box>
 | 
						|
            </Box>
 | 
						|
 | 
						|
            <ShowImageModal src={imageSrc || fallbackSrc} fallbackSrc={fallbackSrc} opened={opened} onClose={close} />
 | 
						|
        </>
 | 
						|
    );
 | 
						|
}
 |