Skip to content

Commit

Permalink
Merge dev (#1)
Browse files Browse the repository at this point in the history
* Added file upload to add modal

* Add PWA manifest
Added more filter options for data table
Minor padding issues for jobid page

* Added status update to main job table

* Dynamic height for edit modal

* Dynamic height for edit modal

* Dynamic height for edit modal

* Dynamic height for edit modal
  • Loading branch information
ncpleslie authored Mar 29, 2024
1 parent b0799d8 commit d1aa426
Show file tree
Hide file tree
Showing 34 changed files with 845 additions and 194 deletions.
1 change: 1 addition & 0 deletions .github/workflows/extension.yml
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ jobs:

build-prod:
environment: production
continue-on-error: true
needs: [test, lint]
runs-on: ubuntu-latest
env:
Expand Down
7 changes: 7 additions & 0 deletions extension/src/pages/popup/routes/jobs/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
LoadingDialog,
useDeleteJobMutation,
useGetJobsSuspenseQuery,
useUpdateJobMutation,
} from "@application-tracker/frontend";
import { Suspense, useEffect } from "react";
import useMessage from "@pages/popup/hooks/use-message.hook";
Expand Down Expand Up @@ -49,6 +50,7 @@ const AllJobsTableAsync: React.FC<AllJobsTableAsyncProps> = ({ token }) => {
const navigate = useNavigate();
const { data: jobs } = useGetJobsSuspenseQuery(token);
const { mutate, isPending: isPendingDelete } = useDeleteJobMutation();
const { mutate: updateJob } = useUpdateJobMutation();

const onDeleteJob = (job: JobResponse) => {
mutate({ jobId: job.id, token });
Expand All @@ -60,6 +62,10 @@ const AllJobsTableAsync: React.FC<AllJobsTableAsyncProps> = ({ token }) => {
});
};

const onUpdateJob = (job: JobResponse) => {
updateJob({ payload: job, token });
};

const onViewJob = (job: JobResponse) => {
navigate({ to: `/jobs/$jobId`, params: { jobId: job.id } });
};
Expand All @@ -70,6 +76,7 @@ const AllJobsTableAsync: React.FC<AllJobsTableAsyncProps> = ({ token }) => {
onDeleteJob={onDeleteJob}
onDeleteJobs={onDeleteJobs}
onViewJob={onViewJob}
onUpdateJob={onUpdateJob}
isPendingDelete={isPendingDelete}
jobs={jobs}
/>
Expand Down
50 changes: 49 additions & 1 deletion frontend/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,57 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Job Down | Application Tracker</title>
<meta
name="description"
content="Track your job applications from applying to hired"
/>
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" />
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
<link
rel="apple-touch-icon"
sizes="57x57"
href="/apple-touch-icon-57x57.png"
/>
<link
rel="apple-touch-icon"
sizes="72x72"
href="/apple-touch-icon-72x72.png"
/>
<link
rel="apple-touch-icon"
sizes="76x76"
href="/apple-touch-icon-76x76.png"
/>
<link
rel="apple-touch-icon"
sizes="114x114"
href="/apple-touch-icon-114x114.png"
/>
<link
rel="apple-touch-icon"
sizes="120x120"
href="/apple-touch-icon-120x120.png"
/>
<link
rel="apple-touch-icon"
sizes="144x144"
href="/apple-touch-icon-144x144.png"
/>
<link
rel="apple-touch-icon"
sizes="152x152"
href="/apple-touch-icon-152x152.png"
/>
<link
rel="apple-touch-icon"
sizes="180x180"
href="/apple-touch-icon-180x180.png"
/>
<link rel="mask-icon" href="/mask-icon.png" color="#FFFFFF" />
<meta name="theme-color" content="#ffffff" />
</head>
<body>
<div id="root"></div>
Expand Down
1 change: 1 addition & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"@radix-ui/react-popover": "^1.0.7",
"@radix-ui/react-radio-group": "^1.1.3",
"@radix-ui/react-scroll-area": "^1.0.5",
"@radix-ui/react-separator": "^1.0.3",
"@radix-ui/react-slot": "^1.0.2",
"@radix-ui/react-tabs": "^1.0.4",
"@t3-oss/env-core": "^0.9.2",
Expand Down
Binary file added frontend/public/apple-touch-icon-114x114.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added frontend/public/apple-touch-icon-120x120.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added frontend/public/apple-touch-icon-144x144.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added frontend/public/apple-touch-icon-152x152.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added frontend/public/apple-touch-icon-180x180.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added frontend/public/apple-touch-icon-57x57.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added frontend/public/apple-touch-icon-72x72.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added frontend/public/apple-touch-icon-76x76.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added frontend/public/apple-touch-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified frontend/public/favicon.ico
Binary file not shown.
26 changes: 26 additions & 0 deletions frontend/public/manifest.webmanifest
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"name": "Job Down | Application Tracker",
"short_name": "Job Down",
"start_url": "/",
"display": "standalone",
"background_color": "#ffffff",
"lang": "en",
"scope": "/",
"description": "Track your job applications from applying to hired",
"theme_color": "#ffffff",
"icons": [
{ "src": "maskable-icon.png", "sizes": "512x512", "type": "image/png" },
{
"src": "maskable-icon.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "any"
},
{
"src": "maskable-icon.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "maskable"
}
]
}
Binary file added frontend/public/maskable-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
155 changes: 111 additions & 44 deletions frontend/src/components/AllJobsTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,42 +12,51 @@ import { DataTable } from "./ui/data-table";
import JobResponse from "@/models/responses/job.response";
import { Checkbox } from "@/components/ui/checkbox";
import { LoadingDialog } from "./ui/loading-dialog";
import { ArrowUpDown, MoreHorizontal } from "lucide-react";
import { useMemo } from "react";
import { ArrowUpDown, MoreHorizontal, PlusSquare } from "lucide-react";
import { useMemo, useState } from "react";
import { snakeCaseToTitleCase } from "@/lib/utils/helper.utils";
import { Card, CardDescription, CardHeader, CardTitle } from "./ui/card";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "./ui/card";
import JobFormConstants from "@/constants/job-form.constants";
import { cn } from "@/lib/utils";
import { Link } from "@tanstack/react-router";
import { DropdownSelectInput } from "./ui/dropdown-select-input";

const statusToBadgeColor = (status: string) => {
switch (status) {
case "applied":
return "bg-blue-500 text-white";
case "phone_screen":
return "bg-yellow-500 text-black";
case "coding_challenge":
return "bg-yellow-500 text-black";
case "first_interview":
return "bg-yellow-500 text-black";
case "second_interview":
return "bg-yellow-500 text-black";
case "final_interview":
return "bg-yellow-500 text-black";
case "offer":
return "bg-green-500 text-white";
case "accepted":
return "bg-green-500 text-white";
case "rejected":
return "bg-red-500 text-white";
default:
return "bg-gray-500 text-white";
}
};

const createColumns = (
onDeleteJob: (job: JobResponse) => void,
onViewJob: (job: JobResponse) => void,
onUpdateJob: (job: JobResponse) => void,
) => {
const statusToBadgeColor = (status: string) => {
switch (status) {
case "applied":
return "bg-blue-500 text-white";
case "phone_screen":
return "bg-yellow-500 text-black";
case "coding_challenge":
return "bg-yellow-500 text-black";
case "first_interview":
return "bg-yellow-500 text-black";
case "second_interview":
return "bg-yellow-500 text-black";
case "final_interview":
return "bg-yellow-500 text-black";
case "offer":
return "bg-green-500 text-white";
case "accepted":
return "bg-green-500 text-white";
case "rejected":
return "bg-red-500 text-white";
default:
return "bg-gray-500 text-white";
}
};

const columns: ColumnDef<JobResponse>[] = [
{
id: "select",
Expand Down Expand Up @@ -89,7 +98,7 @@ const createColumns = (
);
},
cell: ({ row }) => (
<div className="max-w-[19ch] truncate text-ellipsis text-left text-xs md:max-w-full md:text-center lg:text-sm">
<div className="max-w-[15ch] truncate text-ellipsis text-left text-sm md:max-w-full">
{row.getValue("company")}
</div>
),
Expand All @@ -110,14 +119,17 @@ const createColumns = (
},
cell: ({ row }) => {
return (
<div className="max-w-[25ch] text-left text-xs md:max-w-full md:text-center lg:text-sm">
<div className="max-w-[15ch] truncate text-left text-sm md:max-w-full">
{row.getValue("position")}
</div>
);
},
meta: {
className: "p-2 md:p-4",
},
filterFn: (row, id, value) => {
return value.includes(row.getValue(id));
},
},
{
accessorKey: "createdAt",
Expand Down Expand Up @@ -156,22 +168,63 @@ const createColumns = (
</Button>
);
},
cell: ({ row }) => (
<div className="flex justify-center text-center capitalize">
<div
className={cn(
"w-full rounded-lg p-2",
statusToBadgeColor(row.getValue("status") as string),
)}
>
{snakeCaseToTitleCase(row.getValue("status"))}
cell: ({ row }) => {
// Valid JSX is returned but this doesn't start with a capital letter
// eslint-disable-next-line react-hooks/rules-of-hooks
const [updatingJob, setUpdatingJob] = useState<JobResponse | null>(
null,
);
const job = row.original;
const status = row.getValue("status") as string;
// Valid JSX is returned but this doesn't start with a capital letter
// eslint-disable-next-line react-hooks/rules-of-hooks
const statusObj = useMemo(
() => ({
id: status.toLowerCase(),
label: `${status.charAt(0).toUpperCase()}${status.slice(1)}`,
}),
[status],
);
// Valid JSX is returned but this doesn't start with a capital letter
// eslint-disable-next-line react-hooks/rules-of-hooks
const statuses = useMemo(() => {
const statuses = JobFormConstants.JobStatuses;
if (!statuses.find((status) => status.id === statusObj.id)) {
statuses.push(statusObj);
}

return statuses;
}, [statusObj]);

const onSubmit = (newStatus: string) => {
job.status = newStatus;
setUpdatingJob(job);
onUpdateJob(job);
};

return (
<div className="flex justify-center text-center capitalize">
<div
className={cn("w-full rounded-lg", statusToBadgeColor(status))}
>
<DropdownSelectInput
title={snakeCaseToTitleCase(status)}
options={statuses}
currentSelection={status}
onSubmit={onSubmit}
isPendingUpdate={updatingJob?.id === job.id}
/>
</div>
</div>
</div>
),
);
},
meta: {
className: "hidden lg:table-cell",
className: "hidden md:table-cell",
},
sortingFn: "alphanumeric",
filterFn: (row, id, value) => {
return value.includes(row.getValue(id));
},
},
{
id: "actions",
Expand Down Expand Up @@ -214,6 +267,7 @@ interface AllJobsTableProps {
onDeleteJob: (job: JobResponse) => void;
onDeleteJobs: (jobs: JobResponse[]) => void;
onViewJob: (job: JobResponse) => void;
onUpdateJob: (job: JobResponse) => void;
isPendingDelete: boolean;
}

Expand All @@ -223,10 +277,11 @@ const AllJobsTable: React.FC<AllJobsTableProps> = ({
onDeleteJob,
onDeleteJobs,
onViewJob,
onUpdateJob,
}) => {
const columns = useMemo(
() => createColumns(onDeleteJob, onViewJob),
[onDeleteJob, onViewJob],
() => createColumns(onDeleteJob, onViewJob, onUpdateJob),
[onDeleteJob, onViewJob, onUpdateJob],
);

return (
Expand All @@ -236,6 +291,10 @@ const AllJobsTable: React.FC<AllJobsTableProps> = ({
data={jobs}
columns={columns}
onRowDeleteRequested={onDeleteJobs}
filterOptions={{
inputFilterKey: "company",
dropdownFilterKeys: ["status", "position"],
}}
disabledKey={JobFormConstants.DisabledJobStatuses}
/>
) : (
Expand All @@ -244,6 +303,14 @@ const AllJobsTable: React.FC<AllJobsTableProps> = ({
<CardTitle>No Jobs Found</CardTitle>
<CardDescription>Add a new job to get started</CardDescription>
</CardHeader>
<CardContent className="flex w-full justify-center">
<Button variant="outline" asChild>
<Link to="/jobs/add/modal">
<PlusSquare className="mr-2 h-6 w-6" />
New Job
</Link>
</Button>
</CardContent>
</Card>
)}
<LoadingDialog isLoading={isPendingDelete}>Deleting</LoadingDialog>
Expand Down
Loading

0 comments on commit d1aa426

Please sign in to comment.