Skip to content

Commit

Permalink
Designer job view (#48)
Browse files Browse the repository at this point in the history
* Designer Job View

* Formatting Fixes

* Lint Fix + Minor Styling Update
  • Loading branch information
alderwhiteford authored Dec 8, 2023
1 parent ff359d5 commit 44aac7f
Show file tree
Hide file tree
Showing 14 changed files with 413 additions and 64 deletions.
1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"@mui/icons-material": "^5.14.14",
"@mui/material": "^5.14.13",
"@radix-ui/react-slot": "^1.0.2",
"@react-google-maps/api": "^2.19.2",
"@react-oauth/google": "^0.11.1",
"@reduxjs/toolkit": "^1.9.7",
"@stripe/react-stripe-js": "^2.4.0",
Expand Down
66 changes: 63 additions & 3 deletions frontend/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 13 additions & 11 deletions frontend/src/components/Jobs/AvatarCell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ type ProducerCellProps = {
avatar?: string,
firstName?: string,
lastName?: string,
userType: 'designer' | 'producer'
userType: 'designer' | 'producer',
imageOnly: boolean,
size: number,
}

export default function AvatarCell({ firstName, lastName, userType } : ProducerCellProps) {
export default function AvatarCell({ firstName, lastName, userType, imageOnly, size } : ProducerCellProps) {
const avatarOutlineColor = {
designer: '!bg-designer',
producer: '!bg-producer',
Expand All @@ -17,34 +19,34 @@ export default function AvatarCell({ firstName, lastName, userType } : ProducerC
<div className="flex items-center text-base">
<Avatar
sx={{
width: 85,
height: 85,
width: size,
height: size,
marginRight: '20px'
}}
className={avatarOutlineColor[userType]}
>
<Avatar
sx={{
width: 80,
height: 80,
width: size - 5,
height: size - 5,
backgroundColor: "#FFFFFF",
}}
>
<Avatar
sx={{
width: 70,
height: 70
width: size - 15,
height: size - 15,
}}
>
{firstName?.charAt(0)}
{firstName && lastName ? firstName.charAt(0) : undefined}
</Avatar>
</Avatar>
</Avatar>
{(firstName && lastName)
{!imageOnly && ((firstName && lastName)
? firstName + " " + lastName
: userType === "producer"
? "Awaiting Acceptance"
: "User Not Found"}
: "User Not Found")}
</div>
);
}
189 changes: 189 additions & 0 deletions frontend/src/components/Jobs/DesignerJobs/JobViewDesigner.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
import { useState } from "react"
import { jobApi, userApi } from "../../../api/api"
import { JobExtended } from "../JobRow"

import { Divider } from "@mui/material"
import AvatarCell from "../AvatarCell"
import { ReactNode } from "react"
import Map from "../../Map/Map"
import { useApiError } from "../../../hooks/use-api-error"
import router from "../../../router"
import { JobStatus, NEW_USER_ID, User } from "../../../main.types"

type JobViewDesignerProps = {
jobId: string
}

type GridItemProps = {
title: string
children: ReactNode
}

type JobStatusTagProps = {
status: JobStatus,
}

export default function JobViewDesigner({ jobId } : JobViewDesignerProps) {
const [job, setJob] = useState<JobExtended>()
const [producer, setProducer] = useState<User>()

const [getJob, { isUninitialized }] = jobApi.useGetJobMutation()
const [getUser] = userApi.useLazyGetUserQuery()

const { addError, setOpen } = useApiError()

// Retrieve page data:
if (isUninitialized) {
getJob(jobId)
.unwrap()
.then((jobResponse) => {
setJob(jobResponse as JobExtended)
// Retrieve the producer:
if (jobResponse.producerId !== NEW_USER_ID) {
getUser(jobResponse.producerId as string)
.unwrap()
.then((producerResponse) => {
setProducer(producerResponse)
})
.catch(() => {
addError('Failed to load producer information!')
router.navigate({ to: '/jobs' })
setOpen(true)
})
}
})
.catch(() => {
addError('Failed to load job!')
router.navigate({ to: '/jobs' })
setOpen(true)
})
}

const GridItem = ({ title, children } : GridItemProps) => {
return (
<div className='text-[#A4A4A4]'>
<h1 className='font-semibold text-lg text-primary mb-2'>
{title}
</h1>
{children}
</div>
)
}

const JobStatusTag = ({ status } : JobStatusTagProps) => {
console.log(status)

const infoMappings = {
PENDING: {title: 'Pending', styles: 'bg-background !text-primary'},
ACCEPTED: {title: 'Accepted', styles: 'bg-producer'},
INPROGRESS: {title: 'In Progress', styles: 'bg-[#ae7d14]'},
INSHIPPING: {title: 'Shipped', styles: 'bg-[designer]'},
COMPLETE: {title: 'Complete', styles: 'bg-[#14AE5C'}
}

return (
<div className={`p-2 pr-6 pl-6 text-background shadow-md rounded-lg ${infoMappings[status].styles} w-fit`}>
{infoMappings[status].title}
</div>
)
}

// Job information:
const address = (
<>
{job?.shippingAddress.line1},
<br/>
{job?.shippingAddress.city}, {job?.shippingAddress.state}
</>
)
const trackingNumber = job?.status === "INSHIPPING" ? "No Information" : "VX562388751US"
const estimatedDelivery = () => {
const date = new Date(job?.createdAt as Date)
const shippingAdjustedDay = date.getDay() + 10
date.setDate(shippingAdjustedDay)
return date.toDateString()
}
const price = `$${job?.price && (job.price / 100).toFixed(2)} USD`
const orderDate = new Date(job?.createdAt as Date).toDateString()

return (
<div className='flex flex-col w-full'>
<section className='flex items-center justify-between h-32 mt-10'>
{job?.status !== 'PENDING'
? <div>
<h2 className='text-3xl'>
Your purchase with
</h2>
<h1 className='font-semibold text-3xl mt-2'>
{producer?.firstName + " " + producer?.lastName}
</h1>
</div>
: <h1 className='animate-pulse text-3xl'>
Searching for a producer...
</h1>
}
<AvatarCell
firstName='Alder'
lastName='Whiteford'
userType='producer'
imageOnly={true}
size={120}
/>
</section>
<div className='flex flex-row gap-x-5 items-center'>
<h1 className='text-2xl'>
Status
</h1>
{job && <JobStatusTag status={job?.status as JobStatus} /> }
</div>
<Divider
className='!m-0 !mt-10'
/>
<div className='flex flex-wrap justify-between items-center mt-10'>
<div className='grid grid-cols-2 grid-rows-2 gap-y-10 w-full md:w-[50%]'>
<GridItem title={'Delivery Location'}>
{address}
</GridItem>
<GridItem title={'Tracking Number'}>
{trackingNumber}
</GridItem>
<GridItem title={'Estimated Delivery'}>
{estimatedDelivery()}
</GridItem>
<GridItem title={'Price'}>
{price}
</GridItem>
</div>
{job &&
<div className='w-full md:w-[50%]'>
<Map
latitude={job?.shippingAddress.location?.coordinates[1] as number}
longitude={job?.shippingAddress.location?.coordinates[0] as number}
zoom={15}
/>
</div>
}
</div>
<Divider
className='!m-0 !mt-10'
/>
<div className='grid grid-cols-2 grid-rows-2 gap-y-10 md:w-[50%] mt-10'>
<GridItem title={'File Count'}>
{job?.designId.length}
</GridItem>
<GridItem title={'Color'}>
{job?.color}
</GridItem>
<GridItem title={'Filament Type'}>
{job?.filament}
</GridItem>
<GridItem title={'Order Placed'}>
{orderDate}
</GridItem>
</div>
<Divider
className='!m-0 !mt-10'
/>
</div>
)
}
4 changes: 2 additions & 2 deletions frontend/src/components/Jobs/DesignerJobs/JobsDesigner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { Job, PageStatus } from "../../../main.types";
import { resetUser } from "../../../store/userSlice";
import FilterDropDown from "../FilterDropDown";
import TableHeader from "../TableHeader";
import JobRow from "../JobRow";
import JobRow, { JobExtended } from "../JobRow";
import ErrorImage from "../../../assets/hero-image-2.png"

export default function JobsDesigner() {
Expand Down Expand Up @@ -105,7 +105,7 @@ export default function JobsDesigner() {
</TableHead>
<TableBody>
{jobsInView.map((job) =>
<JobRow job={job} type='producer' />
<JobRow job={job as JobExtended} type='producer' />
)}
</TableBody>
</Table>
Expand Down
Loading

0 comments on commit 44aac7f

Please sign in to comment.