Files
stats/apps/start/src/routes/_app.$organizationId.index.tsx
Carl-Gerhard Lindesvärd 81a7e5d62e feat: dashboard v2, esm, upgrades (#211)
* esm

* wip

* wip

* wip

* wip

* wip

* wip

* subscription notice

* wip

* wip

* wip

* fix envs

* fix: update docker build

* fix

* esm/types

* delete dashboard :D

* add patches to dockerfiles

* update packages + catalogs + ts

* wip

* remove native libs

* ts

* improvements

* fix redirects and fetching session

* try fix favicon

* fixes

* fix

* order and resize reportds within a dashboard

* improvements

* wip

* added userjot to dashboard

* fix

* add op

* wip

* different cache key

* improve date picker

* fix table

* event details loading

* redo onboarding completely

* fix login

* fix

* fix

* extend session, billing and improve bars

* fix

* reduce price on 10M
2025-10-16 12:27:44 +02:00

98 lines
2.9 KiB
TypeScript

import { FullPageEmptyState } from '@/components/full-page-empty-state';
import FullPageLoadingState from '@/components/full-page-loading-state';
import { LazyComponent } from '@/components/lazy-component';
import { PageHeader } from '@/components/page-header';
import ProjectCard, {
ProjectCardSkeleton,
} from '@/components/projects/project-card';
import { LinkButton } from '@/components/ui/button';
import { AnimatedSearchInput } from '@/components/ui/data-table/data-table-toolbar';
import { TableButtons } from '@/components/ui/table';
import { useSearchQueryState } from '@/hooks/use-search-query-state';
import { useTRPC } from '@/integrations/trpc/react';
import { PAGE_TITLES, createOrganizationTitle } from '@/utils/title';
import { useQuery } from '@tanstack/react-query';
import { createFileRoute } from '@tanstack/react-router';
import { BoxSelectIcon, PlusIcon } from 'lucide-react';
export const Route = createFileRoute('/_app/$organizationId/')({
component: OrganizationPage,
loader: async ({ context, params }) => {
await context.queryClient.prefetchQuery(
context.trpc.project.list.queryOptions({
organizationId: params.organizationId,
}),
);
},
pendingComponent: FullPageLoadingState,
head: () => {
return {
meta: [
{
title: createOrganizationTitle(PAGE_TITLES.PROJECTS),
},
],
};
},
});
function OrganizationPage() {
const { organizationId } = Route.useParams();
const trpc = useTRPC();
const { data: projects } = useQuery(
trpc.project.list.queryOptions({
organizationId,
}),
);
const { setSearch, search } = useSearchQueryState();
if (!projects?.length) {
return (
<FullPageEmptyState
title="No projects found"
description="Create your first project to get started with analytics."
icon={BoxSelectIcon}
>
<LinkButton icon={PlusIcon} to=".">
Create project
</LinkButton>
</FullPageEmptyState>
);
}
return (
<div className="container p-8">
<PageHeader
title="Projects"
description="All your projects in this workspace"
className="mb-8"
/>
<TableButtons>
<AnimatedSearchInput
placeholder="Search projects"
value={search}
onChange={setSearch}
/>
</TableButtons>
<div className="grid gap-6 md:grid-cols-2">
{projects
.filter((project) => {
if (!search) return true;
return project.name.toLowerCase().includes(search.toLowerCase());
})
.map((project, index) => (
<LazyComponent
lazy={index >= 6}
key={project.id}
fallback={<ProjectCardSkeleton />}
>
<ProjectCard {...project} organizationId={organizationId} />
</LazyComponent>
))}
</div>
</div>
);
}