Skip to content

Commit

Permalink
feature: view job improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
goto-eof committed Apr 30, 2023
1 parent 242e24a commit ccfa6a4
Show file tree
Hide file tree
Showing 4 changed files with 232 additions and 84 deletions.
70 changes: 5 additions & 65 deletions src/components/job/JobOffersRequests.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import {
Skeleton,
Flex,
SimpleGrid,
Grid,
} from '@chakra-ui/react';
import { useEffect, useState } from 'react';
import GenericService from '../../service/GenericService';
Expand All @@ -21,8 +20,9 @@ import Pagination from '../Pagination';
import PaginationUtil from '../../util/PaginationUtil';
import { useNavigate } from 'react-router-dom';
import JobConst from '../../consts/JobConst';
import { StarIcon } from '@chakra-ui/icons';
import UserService from '../../service/UserService';
import Stars from './Stars';
import JobService from '../../service/JobService';

interface Props {
baseUrl: string;
Expand All @@ -46,12 +46,6 @@ export default function JobOffersRequests({ baseUrl, urlCountItems }: Props) {
});
}, []);

const deleteItem = (jobId: number) => {
GenericService.delete('api/v1/job', jobId).then((_) => {
setOffers(offers.filter((offer) => offer.id !== jobId));
});
};

const goToPage = (page: number) => {
GenericService.getAll<Array<Job>>(baseUrl + '/' + page).then((data) => {
setOffers(data);
Expand All @@ -63,9 +57,7 @@ export default function JobOffersRequests({ baseUrl, urlCountItems }: Props) {
<>
<SimpleGrid spacing={3}>
{offers &&
offers.map((item, idx) => (
<JobComponent key={idx} deleteItem={deleteItem} job={item} />
))}
offers.map((item, idx) => <JobComponent key={idx} job={item} />)}
</SimpleGrid>
<Pagination
callback={goToPage}
Expand All @@ -77,34 +69,15 @@ export default function JobOffersRequests({ baseUrl, urlCountItems }: Props) {

interface JobProps {
job: Job;
deleteItem: (jobId: number) => void;
}

function JobComponent({ job, deleteItem }: JobProps) {
function JobComponent({ job }: JobProps) {
const [imageLoaded, setImageLoaded] = useState(false);
const navigate = useNavigate();
const goToViewOfferRequest = (id: number | undefined) => {
navigate('/view/' + id);
};

const goToEditOfferRequest = (id: number | undefined) => {
navigate('/editJob/' + id);
};

const calulateAcceptButtonLabel = () => {
if (job.type === JobConst.TYPE_OFFER) {
return 'Request service';
}
if (job.type === JobConst.TYPE_REQUEST) {
return 'Provide service';
}
throw new Error('Function not implemented.');
};
const deleteJobOfferRequest = (jobId: number | undefined) => {
if (jobId) {
deleteItem(jobId);
}
};
function showUserButtons(job: Job) {
return UserService.isSameUsername(job.author?.username || '');
}
Expand Down Expand Up @@ -179,24 +152,7 @@ function JobComponent({ job, deleteItem }: JobProps) {
variant="solid"
colorScheme="blue"
>
{calulateAcceptButtonLabel()}
</Button>
<Button
variant={'solid'}
colorScheme="red"
mr={3}
display={showUserButtons(job) ? '' : 'none'}
onClick={() => deleteJobOfferRequest(job.id)}
>
Delete
</Button>
<Button
variant={'solid'}
colorScheme="green"
display={showUserButtons(job) ? '' : 'none'}
onClick={() => goToEditOfferRequest(job.id)}
>
Edit
{JobService.calulateAcceptButtonLabel(job)}
</Button>
</Box>
</Box>
Expand All @@ -205,19 +161,3 @@ function JobComponent({ job, deleteItem }: JobProps) {
</Card>
);
}
interface StarsProps {
num: number | undefined;
}
function Stars({ num }: StarsProps) {
return (
<Box as="span">
{Array.from(Array(5).keys()).map((_, idx) => {
return idx < (num || 0) ? (
<StarIcon key={idx} color={'yellow.300'} />
) : (
<StarIcon key={idx} color={'gray.400'} />
);
})}
</Box>
);
}
20 changes: 20 additions & 0 deletions src/components/job/Stars.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { StarIcon } from '@chakra-ui/icons';
import { Box } from '@chakra-ui/react';

export default function Stars({ num }: StarsProps) {
return (
<Box as="span">
{Array.from(Array(5).keys()).map((_, idx) => {
return idx < (num || 0) ? (
<StarIcon key={idx} color={'yellow.300'} />
) : (
<StarIcon key={idx} color={'gray.400'} />
);
})}
</Box>
);
}

interface StarsProps {
num: number | undefined;
}
212 changes: 193 additions & 19 deletions src/components/job/ViewOfferRequest.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,211 @@ import { useEffect, useState } from 'react';
import GenericService from '../../service/GenericService';
import Job from '../../dto/Job';
import { Card, CardBody } from '@chakra-ui/card';
import { Box, Flex, Text } from '@chakra-ui/react';
import { useParams } from 'react-router-dom';
import {
Box,
Image,
Button,
Flex,
Heading,
SimpleGrid,
Skeleton,
Stack,
Text,
CardFooter,
useDisclosure,
Modal,
ModalOverlay,
ModalContent,
ModalHeader,
ModalCloseButton,
ModalBody,
ModalFooter,
} from '@chakra-ui/react';
import { useNavigate, useParams } from 'react-router-dom';
import UserService from '../../service/UserService';
import Stars from './Stars';
import JobService from '../../service/JobService';

interface Props {}
export default function ViewOfferRequest({}: Props) {
const [job, setJob] = useState<Job>();
const [imageLoaded, setImageLoaded] = useState(false);
const { isOpen, onOpen, onClose } = useDisclosure();
const navigate = useNavigate();
const [modalImage, setModalImage] = useState<string>();

let { id } = useParams();
useEffect(() => {
GenericService.get<Job>('api/v1/job/' + id).then((job) => {
setJob(job);
});
}, []);

function showUserButtons(job: Job) {
return UserService.isSameUsername(job.author?.username || '');
}

const goToEditOfferRequest = (id: number | undefined) => {
navigate('/editJob/' + id);
};

const deleteJobOfferRequest = (jobId: number | undefined) => {
if (jobId) {
deleteItem(jobId);
}
};

const deleteItem = (jobId: number) => {
GenericService.delete('api/v1/job', jobId).then((_) => {
// setOffers(offers.filter((offer) => offer.id !== jobId));
navigate('/offers');
});
};

function openModal(image: string) {
setModalImage(image);
onOpen();
}

return (
<Card>
<CardBody>
<Text>ID: {job && job.id}</Text>
<Text>Title: {job && job.title}</Text>
<Text>Description: {job && job.description}</Text>
<Text>Status: {job && job.status}</Text>
<Text>Type: {job && job.type}</Text>
<Flex>
{job &&
job.pictureNamesList &&
job.pictureNamesList.map((image, idx) => (
<Box key={idx} w={'64px'} h={'64px'}>
<img src={'/api/v1/jobPicture/files/' + image} />
<>
<Card
direction={{ base: 'column', sm: 'row' }}
overflow="hidden"
variant="outline"
>
{job && job.pictureName && (
<Skeleton
width={{ base: '100%', sm: '200px' }}
isLoaded={imageLoaded}
>
<Image
onClick={() =>
job && job.pictureName && openModal(job.pictureName)
}
objectFit="cover"
maxW={{ base: '100%', sm: '200px' }}
h={{ base: '100%', sm: '100%' }}
src={'/api/v1/jobPicture/files/' + job.pictureName}
alt="Job Picture"
onLoad={() => setImageLoaded(true)}
/>
</Skeleton>
)}
{job && !job.pictureName && (
<Skeleton
width={{ base: '100%', sm: '200px' }}
isLoaded={imageLoaded}
>
<Image
objectFit="cover"
maxW={{ base: '100%', sm: '200px' }}
h={{ base: '100%', sm: '100%' }}
src={'/api/v1/jobPicture/files/no_image.png'}
alt="Job Picture"
onLoad={() => setImageLoaded(true)}
/>
</Skeleton>
)}

<SimpleGrid columns={{ base: 1, md: 2 }} w={'full'}>
<Stack spacing={4} w={'full'}>
<CardBody>
<Heading
cursor={'pointer'}
color={'blue.400'}
_hover={{ color: 'blue.500' }}
size="md"
>
{job && job.title}{' '}
</Heading>
<Box fontSize={'0.8em'}>
by {job && job.author?.firstname} {job && job.author?.lastname}{' '}
(@
{job && job.author?.username}){' | '}{' '}
<Stars num={job && job.author?.stars} />
</Box>
<Text py="2">{job && job.description}</Text>
</CardBody>
<CardFooter justify={'left'}>
<Flex>
{job &&
job.pictureNamesList &&
job.pictureNamesList.map((image, idx) => (
<Box
onClick={() => openModal(image)}
key={idx}
mr={5}
borderRadius={'10px'}
boxShadow={'md'}
>
<img src={'/api/v1/jobPicture/files/' + image} />
</Box>
))}
</Flex>
</CardFooter>
</Stack>
<Flex w={'full'}>
<Box
borderRadius={'10px'}
verticalAlign={'top'}
w={'full'}
textAlign={'right'}
p={10}
>
<Box textAlign={'right'}>Price:</Box>
<Box fontSize={'1.3em'} fontWeight={'bold'}>
{job && job.price}
</Box>
))}
</Flex>
</CardBody>
</Card>
<Box mt={4}>
<Button
display={job && !showUserButtons(job) ? '' : 'none'}
mr={3}
variant="solid"
colorScheme="blue"
>
{job && JobService.calulateAcceptButtonLabel(job)}
</Button>
<Button
variant={'solid'}
colorScheme="red"
mr={3}
display={job && showUserButtons(job) ? '' : 'none'}
onClick={() => job && deleteJobOfferRequest(job.id)}
>
Delete
</Button>
<Button
variant={'solid'}
colorScheme="green"
display={job && showUserButtons(job) ? '' : 'none'}
onClick={() => job && goToEditOfferRequest(job.id)}
>
Edit
</Button>
</Box>
</Box>
</Flex>
</SimpleGrid>
</Card>
<Modal isOpen={isOpen} size={'full'} onClose={onClose}>
<ModalOverlay />
<ModalContent onClick={onClose}>
<ModalHeader>Modal Title</ModalHeader>
<ModalCloseButton />
<ModalBody>
<Box borderRadius={'10px'} boxShadow={'md'}>
<img src={'/api/v1/jobPicture/files/' + modalImage} />
</Box>
</ModalBody>

<ModalFooter>
<Button colorScheme="blue" mr={3} onClick={onClose}>
Close
</Button>
</ModalFooter>
</ModalContent>
</Modal>
</>
);
}
14 changes: 14 additions & 0 deletions src/service/JobService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import JobConst from '../consts/JobConst';
import Job from '../dto/Job';

export default class JobService {
public static calulateAcceptButtonLabel = (job: Job) => {
if (job.type === JobConst.TYPE_OFFER) {
return 'Request service';
}
if (job.type === JobConst.TYPE_REQUEST) {
return 'Provide service';
}
throw new Error('Function not implemented.');
};
}

0 comments on commit ccfa6a4

Please sign in to comment.