refactor(forms): memoize dynamic form sections with stable ids
continuous-integration/drone/push Build is passing
continuous-integration/drone/push Build is passing
Add uuid-based section keys and memoized DynamicSection to reduce re-renders, fix dashboard GSAP scoping, update logo sizing, and temporarily hide notice-type and closing-soon widgets. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -28,34 +28,41 @@ export function ClosingSoonCard({ tenders, isLoading }: Props) {
|
||||
const rootRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
const root = rootRef.current;
|
||||
if (!root) return;
|
||||
|
||||
const reduced =
|
||||
typeof window !== "undefined" &&
|
||||
window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
||||
const ctx = gsap.context(() => {
|
||||
if (reduced) return;
|
||||
gsap.from(rootRef.current, {
|
||||
gsap.from(root, {
|
||||
opacity: 0,
|
||||
y: 24,
|
||||
duration: 0.6,
|
||||
ease: "power3.out",
|
||||
delay: 0.3,
|
||||
});
|
||||
gsap.from("[data-closing-row]", {
|
||||
x: 24,
|
||||
opacity: 0,
|
||||
duration: 0.45,
|
||||
stagger: 0.07,
|
||||
delay: 0.55,
|
||||
ease: "power2.out",
|
||||
});
|
||||
}, rootRef);
|
||||
|
||||
const rows = root.querySelectorAll("[data-closing-row]");
|
||||
if (rows.length > 0) {
|
||||
gsap.from(rows, {
|
||||
x: 24,
|
||||
opacity: 0,
|
||||
duration: 0.45,
|
||||
stagger: 0.07,
|
||||
delay: 0.55,
|
||||
ease: "power2.out",
|
||||
});
|
||||
}
|
||||
}, root);
|
||||
return () => ctx.revert();
|
||||
}, [tenders.length, isLoading]);
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={rootRef}
|
||||
className="flex h-full flex-col overflow-hidden rounded-2xl bg-white shadow-1 ring-1 ring-stroke dark:bg-gray-dark dark:ring-stroke-dark dark:shadow-card"
|
||||
className="flex h-full flex-col overflow-hidden rounded-2xl bg-white shadow-1 ring-1 ring-stroke dark:bg-gray-dark dark:shadow-card dark:ring-stroke-dark"
|
||||
>
|
||||
<div className="flex items-center justify-between border-b border-stroke px-5 py-4 dark:border-stroke-dark">
|
||||
<div className="flex items-center gap-2">
|
||||
@@ -66,7 +73,9 @@ export function ClosingSoonCard({ tenders, isLoading }: Props) {
|
||||
<h2 className="text-base font-bold text-dark dark:text-white">
|
||||
Closing Soon
|
||||
</h2>
|
||||
<p className="text-xs text-dark-6">Tenders with looming deadlines</p>
|
||||
<p className="text-xs text-dark-6">
|
||||
Tenders with looming deadlines
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<Link
|
||||
@@ -80,7 +89,10 @@ export function ClosingSoonCard({ tenders, isLoading }: Props) {
|
||||
<ul className="flex-1 divide-y divide-stroke dark:divide-stroke-dark">
|
||||
{isLoading
|
||||
? Array.from({ length: 5 }).map((_, i) => (
|
||||
<li key={i} className="flex animate-pulse items-center gap-3 px-5 py-3.5">
|
||||
<li
|
||||
key={i}
|
||||
className="flex animate-pulse items-center gap-3 px-5 py-3.5"
|
||||
>
|
||||
<div className="size-10 rounded-lg bg-gray-2 dark:bg-dark-3" />
|
||||
<div className="flex-1 space-y-2">
|
||||
<div className="h-3 w-3/4 rounded bg-gray-2 dark:bg-dark-3" />
|
||||
|
||||
@@ -53,15 +53,15 @@ export function TenderDashboard() {
|
||||
<CountryDistribution countries={countries} isLoading={isPending} />
|
||||
</div>
|
||||
|
||||
<div className="col-span-12 xl:col-span-5">
|
||||
{/* <div className="col-span-12 xl:col-span-5">
|
||||
<NoticeTypeBreakdown
|
||||
noticeTypes={noticeTypes}
|
||||
isLoading={isPending}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-span-12 xl:col-span-7">
|
||||
</div> */}
|
||||
{/* <div className="col-span-12 xl:col-span-7">
|
||||
<ClosingSoonCard tenders={closingSoonList} isLoading={isPending} />
|
||||
</div>
|
||||
</div> */}
|
||||
|
||||
<div className="col-span-12">
|
||||
<RecentTenders tenders={recent} isLoading={recentIsLoading} />
|
||||
|
||||
@@ -45,34 +45,41 @@ export function RecentTenders({ tenders, isLoading }: Props) {
|
||||
const rootRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
const root = rootRef.current;
|
||||
if (!root) return;
|
||||
|
||||
const reduced =
|
||||
typeof window !== "undefined" &&
|
||||
window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
||||
const ctx = gsap.context(() => {
|
||||
if (reduced) return;
|
||||
gsap.from(rootRef.current, {
|
||||
gsap.from(root, {
|
||||
opacity: 0,
|
||||
y: 24,
|
||||
duration: 0.6,
|
||||
ease: "power3.out",
|
||||
delay: 0.35,
|
||||
});
|
||||
gsap.from("[data-recent-row]", {
|
||||
x: -24,
|
||||
opacity: 0,
|
||||
duration: 0.5,
|
||||
stagger: 0.06,
|
||||
delay: 0.55,
|
||||
ease: "power2.out",
|
||||
});
|
||||
}, rootRef);
|
||||
|
||||
const rows = root.querySelectorAll("[data-recent-row]");
|
||||
if (rows.length > 0) {
|
||||
gsap.from(rows, {
|
||||
x: -24,
|
||||
opacity: 0,
|
||||
duration: 0.5,
|
||||
stagger: 0.06,
|
||||
delay: 0.55,
|
||||
ease: "power2.out",
|
||||
});
|
||||
}
|
||||
}, root);
|
||||
return () => ctx.revert();
|
||||
}, [tenders.length, isLoading]);
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={rootRef}
|
||||
className="flex h-full flex-col overflow-hidden rounded-2xl bg-white shadow-1 ring-1 ring-stroke dark:bg-gray-dark dark:ring-stroke-dark dark:shadow-card"
|
||||
className="flex h-full flex-col overflow-hidden rounded-2xl bg-white shadow-1 ring-1 ring-stroke dark:bg-gray-dark dark:shadow-card dark:ring-stroke-dark"
|
||||
>
|
||||
<div className="flex items-center justify-between border-b border-stroke px-5 py-4 dark:border-stroke-dark">
|
||||
<div className="flex items-center gap-2">
|
||||
|
||||
Reference in New Issue
Block a user