feat: rework-the-loading.tsx-on-people-page (#2668)

Co-authored-by: Johannes <72809645+jobenjada@users.noreply.github.com>
Co-authored-by: Johannes <johannes@formbricks.com>
This commit is contained in:
Lovish Duggal
2024-05-24 18:56:28 +05:30
committed by GitHub
parent 6d6a47a5ac
commit ffa774db6a
12 changed files with 203 additions and 107 deletions

View File

@@ -57,7 +57,7 @@ export const AttributeClassesTable = ({ attributeClasses }: AttributeClassesTabl
{displayedAttributeClasses.map((attributeClass, index) => (
<button
onClick={() => handleOpenAttributeDetailModalClick(attributeClass)}
className="w-full"
className="w-full cursor-default"
key={attributeClass.id}>
<AttributeClassDataRow attributeClass={attributeClass} key={index} />
</button>

View File

@@ -5,7 +5,7 @@ import { Badge } from "@formbricks/ui/Badge";
export const AttributeClassDataRow = ({ attributeClass }) => {
return (
<div className="m-2 grid h-16 grid-cols-5 content-center rounded-lg transition-colors ease-in-out hover:bg-slate-100">
<div className="m-2 grid h-16 cursor-pointer grid-cols-5 content-center rounded-lg transition-colors ease-in-out hover:bg-slate-100">
<div className="col-span-5 flex items-center pl-6 text-sm sm:col-span-3">
<div className="flex items-center">
<TagIcon className="h-5 w-5 flex-shrink-0 text-slate-500" />

View File

@@ -1,42 +1,51 @@
import { PeopleSecondaryNavigation } from "@/app/(app)/environments/[environmentId]/(people)/people/components/PeopleSecondaryNavigation";
import { TagIcon } from "lucide-react";
import { PageContentWrapper } from "@formbricks/ui/PageContentWrapper";
import { PageHeader } from "@formbricks/ui/PageHeader";
const Loading = () => {
return (
<>
<div className="rounded-lg border border-slate-200">
<div className="grid h-12 grid-cols-5 content-center rounded-lg bg-slate-100 text-left text-sm font-semibold text-slate-900">
<div className="col-span-3 pl-6 ">Name</div>
<div className="text-center">Created</div>
<div className="text-center">Last Updated</div>
</div>
</div>
{[...Array(3)].map((_, index) => (
<div key={index} className="m-2 grid h-16 grid-cols-5 content-center rounded-lg hover:bg-slate-100">
<div className="col-span-3 flex items-center pl-6 text-sm">
<div className="flex items-center">
<div className="h-10 w-10 flex-shrink-0">
<TagIcon className="h-8 w-8 flex-shrink-0 animate-pulse text-slate-500" />
</div>
<div className="ml-4 text-left">
<div className="font-medium text-slate-900">
<div className="mt-0 h-4 w-48 animate-pulse rounded-full bg-slate-200"></div>
<PageContentWrapper>
<PageHeader pageTitle="Attributes">
<PeopleSecondaryNavigation activeId="attributes" loading />
</PageHeader>
<div className="rounded-xl border border-slate-200 bg-white shadow-sm">
<div className="grid h-12 grid-cols-5 content-center border-b text-left text-sm font-semibold text-slate-900">
<div className="col-span-3 pl-6 ">Name</div>
<div className="text-center">Created</div>
<div className="text-center">Last Updated</div>
</div>
<div className="w-full">
{[...Array(3)].map((_, index) => (
<div
key={index}
className="m-2 grid h-16 grid-cols-5 content-center rounded-lg transition-colors ease-in-out hover:bg-slate-100">
<div className="col-span-3 flex items-center pl-6 text-sm">
<div className="flex items-center">
<TagIcon className="h-5 w-5 flex-shrink-0 animate-pulse text-slate-500" />
<div className="ml-4 text-left">
<div className="font-medium text-slate-900">
<div className="mt-0 h-4 w-48 animate-pulse rounded-full bg-slate-200"></div>
</div>
<div className="mt-1 text-xs text-slate-400">
<div className="h-2 w-24 animate-pulse rounded-full bg-slate-200"></div>
</div>
</div>
</div>
</div>
<div className="mt-1 text-xs text-slate-400">
<div className="h-2 w-24 animate-pulse rounded-full bg-slate-200"></div>
<div className="my-auto whitespace-nowrap text-center text-sm text-slate-500">
<div className="m-4 h-4 animate-pulse rounded-full bg-slate-200"></div>
</div>
<div className="my-auto whitespace-nowrap text-center text-sm text-slate-500">
<div className="m-4 h-4 animate-pulse rounded-full bg-slate-200"></div>
</div>
</div>
</div>
</div>
<div className="my-auto whitespace-nowrap text-center text-sm text-slate-500">
<div className="m-4 h-4 animate-pulse rounded-full bg-slate-200"></div>
</div>
<div className="my-auto whitespace-nowrap text-center text-sm text-slate-500">
<div className="m-4 h-4 animate-pulse rounded-full bg-slate-200"></div>
))}
</div>
</div>
))}
</PageContentWrapper>
</>
);
};

View File

@@ -29,7 +29,7 @@ const Page = async ({ params }) => {
return (
<PageContentWrapper>
<PageHeader pageTitle="People" cta={HowToAddAttributesButton}>
<PageHeader pageTitle="Attributes" cta={HowToAddAttributesButton}>
<PeopleSecondaryNavigation activeId="attributes" environmentId={params.environmentId} />
</PageHeader>
<AttributeClassesTable attributeClasses={attributeClasses} />

View File

@@ -2,10 +2,11 @@ import { SecondaryNavigation } from "@formbricks/ui/SecondaryNavigation";
interface PeopleSegmentsTabsProps {
activeId: string;
environmentId: string;
environmentId?: string;
loading?: boolean;
}
export const PeopleSecondaryNavigation = ({ activeId, environmentId }: PeopleSegmentsTabsProps) => {
export const PeopleSecondaryNavigation = ({ activeId, environmentId, loading }: PeopleSegmentsTabsProps) => {
const navigation = [
{
id: "people",
@@ -24,5 +25,5 @@ export const PeopleSecondaryNavigation = ({ activeId, environmentId }: PeopleSeg
},
];
return <SecondaryNavigation navigation={navigation} activeId={activeId} />;
return <SecondaryNavigation navigation={navigation} activeId={activeId} loading={loading} />;
};

View File

@@ -14,7 +14,7 @@ export const PersonCard = async ({ person }: { person: TPerson }) => {
href={`/environments/${person.environmentId}/people/${person.id}`}
key={person.id}
className="w-full">
<div className="m-2 grid h-16 grid-cols-7 content-center rounded-lg hover:bg-slate-100">
<div className="m-2 grid h-16 grid-cols-7 content-center rounded-lg transition-colors ease-in-out hover:bg-slate-100">
<div className="col-span-3 flex items-center pl-6 text-sm">
<div className="flex items-center">
<div className="ph-no-capture h-10 w-10 flex-shrink-0">

View File

@@ -1,35 +1,45 @@
import { PeopleSecondaryNavigation } from "@/app/(app)/environments/[environmentId]/(people)/people/components/PeopleSecondaryNavigation";
import { PageContentWrapper } from "@formbricks/ui/PageContentWrapper";
import { PageHeader } from "@formbricks/ui/PageHeader";
const Loading = () => {
return (
<>
<div className="rounded-lg border border-slate-200">
<div className="grid h-12 grid-cols-7 content-center rounded-lg bg-slate-100 text-left text-sm font-semibold text-slate-900">
<div className="col-span-3 pl-6">User</div>
<div className="col-span-2 text-center">User ID</div>
<div className="col-span-2 text-center">Email</div>
</div>
<div className="w-full">
{[...Array(3)].map((_, index) => (
<div
key={index}
className="m-2 grid h-16 grid-cols-7 content-center rounded-lg hover:bg-slate-100">
<div className="col-span-3 flex items-center pl-6 text-sm">
<div className="flex items-center">
<div className="ph-no-capture h-10 w-10 flex-shrink-0 animate-pulse rounded-full bg-gray-200"></div>
<div className="ml-4">
<div className="ph-no-capture h-4 w-28 animate-pulse rounded-full bg-gray-200 font-medium text-slate-900"></div>
<PageContentWrapper>
<PageHeader pageTitle="People">
<PeopleSecondaryNavigation activeId="people" loading />
</PageHeader>
<div className="rounded-xl border border-slate-200 bg-white shadow-sm">
<div className="grid h-12 grid-cols-7 content-center border-b text-left text-sm font-semibold text-slate-900">
<div className="col-span-3 pl-6">User</div>
<div className="col-span-2 text-center">User ID</div>
<div className="col-span-2 text-center">Email</div>
</div>
<div className="w-full">
{[...Array(3)].map((_, index) => (
<div
key={index}
className="m-2 grid h-16 grid-cols-7 content-center rounded-lg transition-colors ease-in-out hover:bg-slate-100">
<div className="col-span-3 flex items-center pl-6 text-sm">
<div className="flex items-center">
<div className="ph-no-capture h-10 w-10 flex-shrink-0 animate-pulse rounded-full bg-gray-200"></div>{" "}
<div className="ml-4">
<div className="ph-no-capture h-4 w-28 animate-pulse rounded-full bg-gray-200 font-medium text-slate-900"></div>
</div>{" "}
</div>
</div>
<div className="col-span-2 my-auto whitespace-nowrap text-center text-sm text-slate-500">
<div className="ph-no-capture m-12 h-4 animate-pulse rounded-full bg-gray-200 text-slate-900"></div>
</div>
<div className="col-span-2 my-auto whitespace-nowrap text-center text-sm text-slate-500">
<div className="ph-no-capture m-12 h-4 animate-pulse rounded-full bg-gray-200 text-slate-900"></div>
</div>
</div>
<div className="col-span-2 my-auto whitespace-nowrap text-center text-sm text-slate-500">
<div className="ph-no-capture m-12 h-4 animate-pulse rounded-full bg-gray-200 text-slate-900"></div>
</div>
<div className="col-span-2 my-auto whitespace-nowrap text-center text-sm text-slate-500">
<div className="ph-no-capture m-12 h-4 animate-pulse rounded-full bg-gray-200 text-slate-900"></div>
</div>
</div>
))}
))}
</div>
</div>
</div>
</PageContentWrapper>
</>
);
};

View File

@@ -18,22 +18,28 @@ export const SegmentTable = ({
isAdvancedTargetingAllowed,
}: TSegmentTableProps) => {
return (
<div className="rounded-lg border border-slate-200">
<div className="grid h-12 grid-cols-7 content-center rounded-lg bg-slate-100 text-left text-sm font-semibold text-slate-900">
<div className="rounded-xl border border-slate-200 bg-white shadow-sm">
<div className="grid h-12 grid-cols-7 content-center border-b text-left text-sm font-semibold text-slate-900">
<div className="col-span-4 pl-6">Title</div>
<div className="col-span-1 hidden text-center sm:block">Surveys</div>
<div className="col-span-1 hidden text-center sm:block">Updated</div>
<div className="col-span-1 hidden text-center sm:block">Created</div>
</div>
{segments.map((segment) => (
<SegmentTableDataRowContainer
currentSegment={segment}
segments={segments}
actionClasses={actionClasses}
attributeClasses={attributeClasses}
isAdvancedTargetingAllowed={isAdvancedTargetingAllowed}
/>
))}
{segments.length === 0 ? (
<p className="py-6 text-center text-sm text-slate-400">Create your first Segment to get started.</p>
) : (
<>
{segments.map((segment) => (
<SegmentTableDataRowContainer
currentSegment={segment}
segments={segments}
actionClasses={actionClasses}
attributeClasses={attributeClasses}
isAdvancedTargetingAllowed={isAdvancedTargetingAllowed}
/>
))}
</>
)}
</div>
);
};

View File

@@ -34,11 +34,11 @@ export const SegmentTableDataRow = ({
<>
<div
key={id}
className="m-2 grid h-16 cursor-pointer grid-cols-7 content-center rounded-lg hover:bg-slate-100"
className="m-2 grid h-16 cursor-pointer grid-cols-7 content-center rounded-lg transition-colors ease-in-out hover:bg-slate-100"
onClick={() => setIsEditSegmentModalOpen(true)}>
<div className="col-span-4 flex items-center pl-6 text-sm">
<div className="flex items-center gap-4">
<div className="ph-no-capture h-8 w-8 flex-shrink-0 text-slate-700">
<div className="ph-no-capture w-8 flex-shrink-0 text-slate-500">
<UsersIcon className="h-5 w-5" />
</div>
<div className="flex flex-col">

View File

@@ -0,0 +1,57 @@
import { PeopleSecondaryNavigation } from "@/app/(app)/environments/[environmentId]/(people)/people/components/PeopleSecondaryNavigation";
import { UsersIcon } from "lucide-react";
import { PageContentWrapper } from "@formbricks/ui/PageContentWrapper";
import { PageHeader } from "@formbricks/ui/PageHeader";
const Loading = () => {
return (
<>
<PageContentWrapper>
<PageHeader pageTitle="Segments">
<PeopleSecondaryNavigation activeId="segments" loading />
</PageHeader>
<div className="rounded-xl border border-slate-200 bg-white shadow-sm">
<div className="grid h-12 grid-cols-7 content-center border-b text-left text-sm font-semibold text-slate-900">
<div className="col-span-4 pl-6">Title</div>
<div className="col-span-1 hidden text-center sm:block">Surveys</div>
<div className="col-span-1 hidden text-center sm:block">Updated</div>
<div className="col-span-1 hidden text-center sm:block">Created</div>
</div>
<div className="w-full">
{[...Array(3)].map((_, index) => (
<div
key={index}
className="m-2 grid h-16 grid-cols-7 content-center rounded-lg transition-colors ease-in-out hover:bg-slate-100">
<div className="col-span-4 flex items-center pl-6 text-sm">
<div className="flex items-center gap-4">
<UsersIcon className="h-5 w-5 flex-shrink-0 animate-pulse text-slate-500" />
<div className="flex flex-col">
<div className="font-medium text-slate-900">
<div className="mt-0 h-4 w-48 animate-pulse rounded-full bg-slate-200"></div>
</div>
<div className="mt-1 text-xs text-slate-900">
<div className="h-2 w-24 animate-pulse rounded-full bg-slate-200"></div>
</div>
</div>
</div>
</div>
<div className="col-span-1 my-auto whitespace-nowrap text-center text-sm text-slate-500">
<div className="m-4 h-4 animate-pulse rounded-full bg-slate-200"></div>
</div>
<div className="whitespace-wrap col-span-1 my-auto text-center text-sm text-slate-500">
<div className="m-4 h-4 animate-pulse rounded-full bg-slate-200"></div>
</div>
<div className="col-span-1 my-auto whitespace-normal text-center text-sm text-slate-500">
<div className="m-4 h-4 animate-pulse rounded-full bg-slate-200"></div>
</div>
</div>
))}
</div>
</div>
</PageContentWrapper>
</>
);
};
export default Loading;

View File

@@ -11,7 +11,6 @@ import { IS_FORMBRICKS_CLOUD } from "@formbricks/lib/constants";
import { getEnvironment } from "@formbricks/lib/environment/service";
import { getSegments } from "@formbricks/lib/segment/service";
import { getTeamByEnvironmentId } from "@formbricks/lib/team/service";
import { EmptySpaceFiller } from "@formbricks/ui/EmptySpaceFiller";
import { PageContentWrapper } from "@formbricks/ui/PageContentWrapper";
import { PageHeader } from "@formbricks/ui/PageHeader";
@@ -70,24 +69,15 @@ const Page = async ({ params }) => {
return (
<PageContentWrapper>
<PageHeader pageTitle="People" cta={renderCreateSegmentButton()}>
<PageHeader pageTitle="Segments" cta={renderCreateSegmentButton()}>
<PeopleSecondaryNavigation activeId="segments" environmentId={params.environmentId} />
</PageHeader>
{filteredSegments.length === 0 ? (
<EmptySpaceFiller
type="table"
environment={environment}
emptyMessage="No segments yet. Add your first one to get started."
noWidgetRequired={true}
/>
) : (
<SegmentTable
segments={filteredSegments}
actionClasses={actionClasses}
attributeClasses={attributeClasses}
isAdvancedTargetingAllowed={isAdvancedTargetingAllowed}
/>
)}
<SegmentTable
segments={filteredSegments}
actionClasses={actionClasses}
attributeClasses={attributeClasses}
isAdvancedTargetingAllowed={isAdvancedTargetingAllowed}
/>
</PageContentWrapper>
);
};

View File

@@ -5,28 +5,51 @@ import { cn } from "@formbricks/lib/cn";
interface SecondaryNavbarProps {
navigation: { id: string; label: string; href: string; icon?: React.ReactNode; hidden?: boolean }[];
activeId: string;
loading?: boolean;
}
export const SecondaryNavigation = ({ navigation, activeId, ...props }: SecondaryNavbarProps) => {
export const SecondaryNavigation = ({ navigation, activeId, loading, ...props }: SecondaryNavbarProps) => {
return (
<div {...props}>
<div className="grid h-10 w-full grid-cols-[auto,1fr] ">
<nav className="flex h-full min-w-full items-center space-x-4" aria-label="Tabs">
{navigation.map((navElem) => (
<Link
key={navElem.id}
href={navElem.href}
className={cn(
navElem.id === activeId
? "border-brand-dark border-b-2 font-semibold text-slate-900"
: "border-transparent text-slate-500 transition-all duration-150 ease-in-out hover:border-slate-300 hover:text-slate-700",
"flex h-full items-center border-b-2 px-3 text-sm font-medium",
navElem.hidden && "hidden"
)}
aria-current={navElem.id === activeId ? "page" : undefined}>
{navElem.label}
</Link>
))}
{loading ? (
<>
{navigation.map((navElem) => (
<span
key={navElem.id}
aria-disabled="true"
className={cn(
navElem.id === activeId
? "border-slate600-dark border-b-2 font-semibold text-slate-900"
: "border-transparent text-slate-500",
"flex h-full items-center border-b-2 px-3 text-sm font-medium",
navElem.hidden && "hidden"
)}
aria-current={navElem.id === activeId ? "page" : undefined}>
{navElem.label}
</span>
))}
</>
) : (
<>
{navigation.map((navElem) => (
<Link
key={navElem.id}
href={navElem.href}
className={cn(
navElem.id === activeId
? "border-brand-dark border-b-2 font-semibold text-slate-900"
: "border-transparent text-slate-500 transition-all duration-150 ease-in-out hover:border-slate-300 hover:text-slate-700",
"flex h-full items-center border-b-2 px-3 text-sm font-medium",
navElem.hidden && "hidden"
)}
aria-current={navElem.id === activeId ? "page" : undefined}>
{navElem.label}
</Link>
))}
</>
)}
</nav>
<div className="justify-self-end"></div>
</div>