Skip to content

Commit

Permalink
Merge pull request #18 from ElemarJR/improving_ui
Browse files Browse the repository at this point in the history
Improving UI
  • Loading branch information
ElemarJR authored Oct 28, 2024
2 parents ab8aa4e + 4bac6fe commit 2dbe1fe
Show file tree
Hide file tree
Showing 36 changed files with 2,886 additions and 1,021 deletions.
6 changes: 5 additions & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,14 @@
"@headlessui/react": "^2.1.9",
"@heroicons/react": "^2.1.5",
"@radix-ui/react-alert-dialog": "^1.1.2",
"@radix-ui/react-avatar": "^1.1.1",
"@radix-ui/react-dialog": "^1.1.2",
"@radix-ui/react-dropdown-menu": "^2.1.2",
"@radix-ui/react-hover-card": "^1.1.2",
"@radix-ui/react-icons": "^1.3.0",
"@radix-ui/react-popover": "^1.1.2",
"@radix-ui/react-select": "^2.1.2",
"@radix-ui/react-separator": "^1.1.0",
"@radix-ui/react-slot": "^1.1.0",
"@radix-ui/react-tooltip": "^1.1.3",
"@react-spring/web": "^9.7.5",
Expand All @@ -25,7 +29,7 @@
"date-fns": "^3.6.0",
"framer-motion": "^11.11.0",
"graphql": "^16.9.0",
"lucide-react": "^0.447.0",
"lucide-react": "^0.453.0",
"next": "14.2.14",
"next-auth": "^4.24.8",
"next-themes": "^0.3.0",
Expand Down
Binary file modified frontend/public/images/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
338 changes: 191 additions & 147 deletions frontend/src/app/about-us/account-managers/page.tsx

Large diffs are not rendered by default.

266 changes: 140 additions & 126 deletions frontend/src/app/about-us/cases/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import { useState, useEffect } from "react";
import { Stat } from "@/app/components/analytics/stat";
import { Divider } from "@/components/catalyst/divider";
import { motion, AnimatePresence } from "framer-motion";
import { GET_CASES_AND_TIMESHEET } from './queries';
import { CaseCard } from './CaseCard';
import { FilterFieldsSelect } from '@/app/components/FilterFieldsSelect';
import { GET_CASES_AND_TIMESHEET } from "./queries";
import { CaseCard } from "./CaseCard";
import { FilterFieldsSelect } from "@/app/components/FilterFieldsSelect";
import { Option } from "react-tailwindcss-select/dist/components/type";

export default function Cases() {
Expand All @@ -19,13 +19,18 @@ export default function Cases() {

const { loading, error, data } = useQuery(GET_CASES_AND_TIMESHEET, {
variables: {
filters: formattedSelectedValues.length > 0 ? formattedSelectedValues : null,
filters:
formattedSelectedValues.length > 0 ? formattedSelectedValues : null,
},
});
const [selectedStat, setSelectedStat] = useState<string>('allCases');
const [selectedStat, setSelectedStat] = useState<string>("allCases");

const handleFilterChange = (value: Option | Option[] | null): void => {
const newSelectedValues = Array.isArray(value) ? value : value ? [value] : [];
const newSelectedValues = Array.isArray(value)
? value
: value
? [value]
: [];
setSelectedFilters(newSelectedValues);

const formattedValues =
Expand Down Expand Up @@ -59,23 +64,27 @@ export default function Cases() {

const getStatClassName = (statName: string) => {
return `cursor-pointer transition-all duration-300 ${
selectedStat === statName ? 'ring-2 ring-black shadow-lg scale-105' : 'hover:scale-102'
selectedStat === statName
? "ring-2 ring-black shadow-lg scale-105"
: "hover:scale-102"
}`;
};

const filteredCases = data.cases.filter((caseItem: any) => {
const caseData = data.timesheet.byCase.find((c: any) => c.title === caseItem.title);
if (!caseData) return selectedStat === 'allCases';
const caseData = data.timesheet.byCase.find(
(c: any) => c.title === caseItem.title
);
if (!caseData) return selectedStat === "allCases";
switch (selectedStat) {
case 'total':
case "total":
return caseData.totalHours > 0;
case 'consulting':
case "consulting":
return caseData.totalConsultingHours > 0;
case 'handsOn':
case "handsOn":
return caseData.totalHandsOnHours > 0;
case 'squad':
case "squad":
return caseData.totalSquadHours > 0;
case 'internal':
case "internal":
return caseData.totalInternalHours > 0;
default:
return true;
Expand All @@ -84,132 +93,137 @@ export default function Cases() {

return (
<>
<div className="flex w-full flex-wrap items-end justify-between gap-4 border-b border-zinc-950/10 mb-4 dark:border-white/10">
<Heading className="text-3xl font-bold text-gray-900">Cases</Heading>
</div>
<div className="container mx-auto">
<div className="grid grid-cols-6 gap-4 mb-4">
<div className="col-span-1"></div>
<div className="col-span-5">
<FilterFieldsSelect
data={data.timesheet}
selectedFilters={selectedFilters}
handleFilterChange={handleFilterChange}
/>
</div>
<div className="grid grid-cols-6 gap-4 mb-4">
<div className="col-span-1"></div>
<div className="col-span-5">
<FilterFieldsSelect
data={data.timesheet}
selectedFilters={selectedFilters}
handleFilterChange={handleFilterChange}
/>
</div>
<div className="grid grid-cols-6 gap-4 mb-8">
<div className="col-span-6">
<div className="grid grid-cols-1 lg:grid-cols-6 gap-4">
<div className="lg:col-span-1">
<div className="flex items-center mb-3">
<p className="text-sm font-semibold text-gray-900 uppercase">
ALL TIME
</p>
<div className="flex-grow h-px bg-gray-200 ml-2"></div>
</div>
<div className="grid grid-cols-6 gap-4 mb-8">
<div className="col-span-6">
<div className="grid grid-cols-1 lg:grid-cols-6 gap-4">
<div className="lg:col-span-1">
<div className="flex items-center mb-3">
<p className="text-sm font-semibold text-gray-900 uppercase">
ALL TIME
</p>
<div className="flex-grow h-px bg-gray-200 ml-2"></div>
</div>
<div
className={`${getStatClassName("allCases")} transform`}
onClick={() => handleStatClick("allCases")}
>
<Stat title="All Cases" value={data.cases.length.toString()} />
</div>
</div>
<div className="lg:col-span-5">
<div className="flex items-center mb-3">
<p className="text-sm font-semibold text-gray-900 uppercase">
ACTIVE{" "}
<span className="text-xs text-gray-600 uppercase">
LAST SIX WEEKS
</span>
</p>
<div className="flex-grow h-px bg-gray-200 ml-2"></div>
</div>
<div className="grid grid-cols-1 lg:grid-cols-5 gap-4">
<div
className={`${getStatClassName("total")} transform`}
onClick={() => handleStatClick("total")}
>
<Stat
title="Active Cases"
value={data.timesheet.byCase.length.toString()}
/>
</div>
<div
className={`${getStatClassName('allCases')} transform`}
onClick={() => handleStatClick('allCases')}
className={`${getStatClassName("consulting")} transform`}
onClick={() => handleStatClick("consulting")}
>
<Stat
title="All Cases"
value={data.cases.length.toString()}
title="Consulting"
value={data.timesheet.byCase
.filter((c: any) => c.totalConsultingHours > 0)
.length.toString()}
color="#F59E0B"
total={data.timesheet.byCase.length}
/>
</div>
</div>
<div className="lg:col-span-5">
<div className="flex items-center mb-3">
<p className="text-sm font-semibold text-gray-900 uppercase">
ACTIVE <span className="text-xs text-gray-600 uppercase">LAST SIX WEEKS</span>
</p>
<div className="flex-grow h-px bg-gray-200 ml-2"></div>
<div
className={`${getStatClassName("handsOn")} transform`}
onClick={() => handleStatClick("handsOn")}
>
<Stat
title="Hands-On"
value={data.timesheet.byCase
.filter((c: any) => c.totalHandsOnHours > 0)
.length.toString()}
color="#8B5CF6"
total={data.timesheet.byCase.length}
/>
</div>
<div className="grid grid-cols-1 lg:grid-cols-5 gap-4">
<div
className={`${getStatClassName('total')} transform`}
onClick={() => handleStatClick('total')}
>
<Stat
title="Active Cases"
value={data.timesheet.byCase.length.toString()}
/>
</div>
<div
className={`${getStatClassName('consulting')} transform`}
onClick={() => handleStatClick('consulting')}
>
<Stat
title="Consulting"
value={data.timesheet.byCase.filter((c: any) => c.totalConsultingHours > 0).length.toString()}
color="#F59E0B"
total={data.timesheet.byCase.length}
/>
</div>
<div
className={`${getStatClassName('handsOn')} transform`}
onClick={() => handleStatClick('handsOn')}
>
<Stat
title="Hands-On"
value={data.timesheet.byCase.filter((c: any) => c.totalHandsOnHours > 0).length.toString()}
color="#8B5CF6"
total={data.timesheet.byCase.length}
/>
</div>
<div
className={`${getStatClassName('squad')} transform`}
onClick={() => handleStatClick('squad')}
>
<Stat
title="Squad"
value={data.timesheet.byCase.filter((c: any) => c.totalSquadHours > 0).length.toString()}
color="#3B82F6"
total={data.timesheet.byCase.length}
/>
</div>
<div
className={`${getStatClassName('internal')} transform`}
onClick={() => handleStatClick('internal')}
>
<Stat
title="Internal"
value={data.timesheet.byCase.filter((c: any) => c.totalInternalHours > 0).length.toString()}
color="#10B981"
total={data.timesheet.byCase.length}
/>
</div>
<div
className={`${getStatClassName("squad")} transform`}
onClick={() => handleStatClick("squad")}
>
<Stat
title="Squad"
value={data.timesheet.byCase
.filter((c: any) => c.totalSquadHours > 0)
.length.toString()}
color="#3B82F6"
total={data.timesheet.byCase.length}
/>
</div>
<div
className={`${getStatClassName("internal")} transform`}
onClick={() => handleStatClick("internal")}
>
<Stat
title="Internal"
value={data.timesheet.byCase
.filter((c: any) => c.totalInternalHours > 0)
.length.toString()}
color="#10B981"
total={data.timesheet.byCase.length}
/>
</div>
</div>
</div>
</div>
</div>
<Divider className="my-8" />
<AnimatePresence>
<motion.div
className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-6"
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -20 }}
transition={{ duration: 0.3 }}
>
{filteredCases.map((caseItem: any) => (
<motion.div
key={caseItem.slug}
initial={{ opacity: 0, scale: 0.9 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.9 }}
transition={{ duration: 0.2 }}
>
<CaseCard
caseItem={caseItem}
caseData={data.timesheet.byCase.find((c: any) => c.title === caseItem.title)}
/>
</motion.div>
))}
</motion.div>
</AnimatePresence>
</div>
<Divider className="my-8" />
<AnimatePresence>
<motion.div
className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-6"
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -20 }}
transition={{ duration: 0.3 }}
>
{filteredCases.map((caseItem: any) => (
<motion.div
key={caseItem.slug}
initial={{ opacity: 0, scale: 0.9 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.9 }}
transition={{ duration: 0.2 }}
>
<CaseCard
caseItem={caseItem}
caseData={data.timesheet.byCase.find(
(c: any) => c.title === caseItem.title
)}
/>
</motion.div>
))}
</motion.div>
</AnimatePresence>
</>
);
}
Loading

0 comments on commit 2dbe1fe

Please sign in to comment.