Skip to content

Commit

Permalink
add render component for managing loading (#1041)
Browse files Browse the repository at this point in the history
  • Loading branch information
alexbeno authored Feb 28, 2025
1 parent 040359b commit 9289e7d
Show file tree
Hide file tree
Showing 5 changed files with 290 additions and 103 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,15 @@ import { ProjectInterfaceV2 } from "@/core/domain/project/models/project-model-v
import { Icon } from "@/design-system/atoms/icon";

import { ImageBanner } from "@/shared/features/image-banner/image-banner";
import { RenderComponent } from "@/shared/features/render-component/render-component";
import { RepoLink } from "@/shared/features/repos/repo-link/repo-link";
import { ProjectMoreInfo } from "@/shared/features/social/project-more-info/project-more-info";
import { useContributorSidePanel } from "@/shared/panels/contributor-sidepanel/contributor-sidepanel.hooks";
import { usePosthog } from "@/shared/tracking/posthog/use-posthog";
import { Avatar, AvatarGroup } from "@/shared/ui/avatar";
import { Badge } from "@/shared/ui/badge";
import { Button } from "@/shared/ui/button";
import { Skeleton } from "@/shared/ui/skeleton";
import { Tooltip, TooltipContent, TooltipTrigger } from "@/shared/ui/tooltip";
import { TypographyH2, TypographyMuted, TypographyP, TypographySmall } from "@/shared/ui/typography";
import { cn } from "@/shared/utils";
Expand Down Expand Up @@ -288,7 +290,11 @@ function AlertButton({ projectId, projectName }: { projectId: string; projectNam
}

export function PageHeader({ projectSlug }: PageHeaderProps) {
const { data: project, isLoading } = ProjectReactQueryAdapter.client.useGetProjectBySlugOrId({
const {
data: project,
isLoading,
isError,
} = ProjectReactQueryAdapter.client.useGetProjectBySlugOrId({
pathParams: {
projectIdOrSlug: projectSlug,
},
Expand All @@ -298,59 +304,69 @@ export function PageHeader({ projectSlug }: PageHeaderProps) {
});

return (
<div className="flex w-full flex-col bg-background pt-6">
<ImageBanner isLoading={isLoading} image={project?.logoUrl} className="h-44 w-full rounded-xl">
{project?.id && (
<div className="absolute inset-0 hidden items-center justify-end pr-3 tablet:flex">
<LatestNews projectId={project?.id} />
</div>
)}
</ImageBanner>
<div className="relative z-[2] -mt-12 mb-6 ml-2 flex flex-row items-end justify-between tablet:-mt-16 tablet:ml-6">
<Avatar className="h-24 w-24 rounded-xl border-4 border-background bg-background tablet:h-32 tablet:w-32">
<AvatarImage src={project?.logoUrl} alt={project?.name} className="h-full w-full object-cover" />
<AvatarFallback>
<img className="h-full w-full object-cover" src={onlydustLogoSpace?.src} alt={project?.name} />
</AvatarFallback>
</Avatar>

<div className="flex items-center justify-end gap-3 tablet:hidden">
<ActionHeader projectId={project?.id} />
<RenderComponent isLoading={isLoading} isError={isError}>
<RenderComponent.Loading>
<div className="flex w-full flex-col bg-background pb-8 pt-6">
<Skeleton className="h-[300px] w-full" />
</div>
</div>
<div className="flex w-full flex-col gap-6 px-0">
<div className="flex w-full flex-col gap-2">
<div className="flex w-full items-center justify-between gap-1">
<TypographyH2>{project?.name}</TypographyH2>
<div className="flex items-center justify-end gap-3">
{project?.id && <AlertButton projectId={project.id} projectName={project.name} />}
{project?.id && <BookMarkButton projectId={project.id} projectName={project.name} />}
<div className="hidden tablet:block">
<ActionHeader projectId={project?.id} />
</RenderComponent.Loading>
<RenderComponent.Error errorMessage="Error loading overview" />
<RenderComponent.Default>
<div className="flex w-full flex-col bg-background pt-6">
<ImageBanner isLoading={isLoading} image={project?.logoUrl} className="h-44 w-full rounded-xl">
{project?.id && (
<div className="absolute inset-0 hidden items-center justify-end pr-3 tablet:flex">
<LatestNews projectId={project?.id} />
</div>
)}
</ImageBanner>
<div className="relative z-[2] -mt-12 mb-6 ml-2 flex flex-row items-end justify-between tablet:-mt-16 tablet:ml-6">
<Avatar className="h-24 w-24 rounded-xl border-4 border-background bg-background tablet:h-32 tablet:w-32">
<AvatarImage src={project?.logoUrl} alt={project?.name} className="h-full w-full object-cover" />
<AvatarFallback>
<img className="h-full w-full object-cover" src={onlydustLogoSpace?.src} alt={project?.name} />
</AvatarFallback>
</Avatar>

<div className="flex items-center justify-end gap-3 tablet:hidden">
<ActionHeader projectId={project?.id} />
</div>
</div>
<TypographyP className="text-muted-foreground">{project?.shortDescription}</TypographyP>
</div>
<div className="flex flex-row flex-wrap divide-x">
<Categories categories={project?.categories?.map(category => category.name) ?? []} />
<Languages languages={project?.languages ?? []} />
<Leads leads={project?.leads ?? []} />
</div>
<div className="flex flex-row flex-wrap justify-between gap-4">
<Stats project={project} />
<div className="flex w-full flex-col gap-6 px-0">
<div className="flex w-full flex-col gap-2">
<div className="flex w-full items-center justify-between gap-1">
<TypographyH2>{project?.name}</TypographyH2>
<div className="flex items-center justify-end gap-3">
{project?.id && <AlertButton projectId={project.id} projectName={project.name} />}
{project?.id && <BookMarkButton projectId={project.id} projectName={project.name} />}
<div className="hidden tablet:block">
<ActionHeader projectId={project?.id} />
</div>
</div>
</div>
<TypographyP className="text-muted-foreground">{project?.shortDescription}</TypographyP>
</div>
<div className="flex flex-row flex-wrap divide-x">
<Categories categories={project?.categories?.map(category => category.name) ?? []} />
<Languages languages={project?.languages ?? []} />
<Leads leads={project?.leads ?? []} />
</div>
<div className="flex flex-row flex-wrap justify-between gap-4">
<Stats project={project} />

<div className={"flex flex-row flex-wrap gap-2"}>
{project?.moreInfos?.map(moreInfoItem => (
<ProjectMoreInfo key={moreInfoItem.url} moreInfoItem={moreInfoItem} buttonProps={{ size: "xs" }} />
))}
<div className={"flex flex-row flex-wrap gap-2"}>
{project?.moreInfos?.map(moreInfoItem => (
<ProjectMoreInfo key={moreInfoItem.url} moreInfoItem={moreInfoItem} buttonProps={{ size: "xs" }} />
))}
</div>
</div>
<Repos repos={project?.repos ?? []} />
</div>
<div className="w-full px-0 py-8">
<ProjectNavigation params={{ projectSlug }} />
</div>
</div>
<Repos repos={project?.repos ?? []} />
</div>
<div className="w-full px-0 py-8">
<ProjectNavigation params={{ projectSlug }} />
</div>
</div>
</RenderComponent.Default>
</RenderComponent>
);
}
94 changes: 53 additions & 41 deletions app/(saas)/projects/[projectSlug]/overview/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,18 @@ import { ScrollView } from "@/shared/components/scroll-view/scroll-view";
import { NEXT_ROUTER } from "@/shared/constants/router";
import { NavigationBreadcrumb } from "@/shared/features/navigation/navigation.context";
import { ProjectActivityGraph } from "@/shared/features/project-activity-graph/project-activity-graph";
import { RenderComponent } from "@/shared/features/render-component/render-component";
import { PosthogCaptureOnMount } from "@/shared/tracking/posthog/posthog-capture-on-mount/posthog-capture-on-mount";
import { Translate } from "@/shared/translation/components/translate/translate";
import { Skeleton } from "@/shared/ui/skeleton";

import { Description } from "./_features/description/description";
import { Languages } from "./_features/languages/languages";
import { LatestNews } from "./_features/latest-news/latest-news";
import { SimilarProjects } from "./_features/similar-projects/similar-projects";

function ProjectOverviewPage({ params }: { params: { projectSlug: string } }) {
const { data } = ProjectReactQueryAdapter.client.useGetProjectBySlugOrId({
const { data, isLoading, isError } = ProjectReactQueryAdapter.client.useGetProjectBySlugOrId({
pathParams: {
projectIdOrSlug: params.projectSlug,
},
Expand All @@ -29,6 +31,8 @@ function ProjectOverviewPage({ params }: { params: { projectSlug: string } }) {
},
});

console.log("isLoading", isLoading);

return (
<ScrollView>
<PosthogCaptureOnMount
Expand Down Expand Up @@ -61,49 +65,57 @@ function ProjectOverviewPage({ params }: { params: { projectSlug: string } }) {
]}
/>

<div className="grid w-full grid-cols-1 gap-6 overflow-hidden lg:grid-cols-4">
{data?.id && (
<div className="col-span-full tablet:hidden">
<LatestNews projectId={data?.id} className="w-full max-w-full border-border bg-card" />
</div>
)}
{data?.overview && (
<div className="col-span-full">
<Description
description={data?.overview}
projectId={data?.id}
title={"Overview by OnlyDust"}
isAiGenerated
/>
</div>
)}
{data?.longDescription && (
<div className="col-span-full">
<Description description={data?.longDescription} projectId={data?.id} title={"Description"} />
</div>
)}
<div className="grid lg:col-span-1">
<Languages projectId={data?.id} />
</div>
<div className="grid lg:col-span-3">
<ProjectActivityGraph projectIdOrSlug={params.projectSlug} />
</div>
<div className="grid lg:col-span-2">
<GoodFirstIssues projectId={data?.id} />
</div>
<RenderComponent isLoading={isLoading} isError={isError}>
<RenderComponent.Loading>
<Skeleton className="h-screen w-full" />
</RenderComponent.Loading>
<RenderComponent.Error errorMessage="Error loading overview" />
<RenderComponent.Default>
<div className="grid w-full grid-cols-1 gap-6 overflow-hidden lg:grid-cols-4">
{data?.id && (
<div className="col-span-full tablet:hidden">
<LatestNews projectId={data?.id} className="w-full max-w-full border-border bg-card" />
</div>
)}
{data?.overview && (
<div className="col-span-full">
<Description
description={data?.overview}
projectId={data?.id}
title={"Overview by OnlyDust"}
isAiGenerated
/>
</div>
)}
{data?.longDescription && (
<div className="col-span-full">
<Description description={data?.longDescription} projectId={data?.id} title={"Description"} />
</div>
)}
<div className="grid lg:col-span-1">
<Languages projectId={data?.id} />
</div>
<div className="grid lg:col-span-3">
<ProjectActivityGraph projectIdOrSlug={params.projectSlug} />
</div>
<div className="grid lg:col-span-2">
<GoodFirstIssues projectId={data?.id} />
</div>

<div className="grid lg:col-span-2">
<AvailableIssues projectId={data?.id} />
</div>
<div className="grid lg:col-span-2">
<AvailableIssues projectId={data?.id} />
</div>

<div className="grid lg:col-span-2">
<RecentActivity projectId={data?.id} />
</div>
<div className="grid lg:col-span-2">
<RecentActivity projectId={data?.id} />
</div>

<div className="grid lg:col-span-2">
<SimilarProjects projectIdOrSlug={params.projectSlug} projectId={data?.id} />
</div>
</div>
<div className="grid lg:col-span-2">
<SimilarProjects projectIdOrSlug={params.projectSlug} projectId={data?.id} />
</div>
</div>
</RenderComponent.Default>
</RenderComponent>
</ScrollView>
);
}
Expand Down
43 changes: 29 additions & 14 deletions shared/features/app/app-header/app-header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { AppUserMenu } from "@/shared/features/app/app-user-menu/app-user-menu";
import { GlobalSearch } from "@/shared/features/global-search/global-search";
import { useNavigation } from "@/shared/features/navigation/navigation.context";
import { NotificationsPopover } from "@/shared/features/notifications/notifications-popover";
import { IsAuthenticated, SignInButton } from "@/shared/providers/auth-provider";
import { IsAuthenticated, SignInButton, useAuthContext } from "@/shared/providers/auth-provider";
import {
Breadcrumb,
BreadcrumbItem,
Expand All @@ -15,10 +15,13 @@ import {
} from "@/shared/ui/breadcrumb";
import { Separator } from "@/shared/ui/separator";
import { SidebarTrigger } from "@/shared/ui/sidebar";
import { Skeleton } from "@/shared/ui/skeleton";

import { RenderComponent } from "../../render-component/render-component";

export function AppHeader() {
const { breadcrumb } = useNavigation();

const { isLoading } = useAuthContext();
return (
<header className="sticky top-0 z-[39] flex h-16 shrink-0 items-center gap-2 border-b bg-background/80 px-4 backdrop-blur-sm">
<div className="flex items-center gap-2">
Expand Down Expand Up @@ -46,20 +49,32 @@ export function AppHeader() {
</Breadcrumb>
</div>

<div className={"flex flex-1 flex-row items-center justify-end gap-3"}>
<IsAuthenticated>
<IsAuthenticated.Yes>
<GlobalSearch />
<RenderComponent isLoading={isLoading} classNames={{ default: "flex flex-1", loading: "flex flex-1" }}>
<RenderComponent.Loading>
<div className={"flex flex-1 flex-row items-center justify-end gap-3"}>
<Skeleton className="h-9 w-36" />
<Skeleton className="h-9 w-9" />
<Skeleton className="h-9 w-9" />
</div>
</RenderComponent.Loading>
<RenderComponent.Error errorMessage="Error loading overview" />
<RenderComponent.Default>
<div className={"flex flex-1 flex-row items-center justify-end gap-3"}>
<IsAuthenticated>
<IsAuthenticated.Yes>
<GlobalSearch />

<NotificationsPopover />
<NotificationsPopover />

<AppUserMenu />
</IsAuthenticated.Yes>
<IsAuthenticated.No>
<SignInButton />
</IsAuthenticated.No>
</IsAuthenticated>
</div>
<AppUserMenu />
</IsAuthenticated.Yes>
<IsAuthenticated.No>
<SignInButton />
</IsAuthenticated.No>
</IsAuthenticated>
</div>
</RenderComponent.Default>
</RenderComponent>
</header>
);
}
Loading

0 comments on commit 9289e7d

Please sign in to comment.