diff --git a/src/app/dashboard/studies/[id]/edit/page.tsx b/src/app/dashboard/studies/[id]/edit/page.tsx
index d47904c..430779f 100644
--- a/src/app/dashboard/studies/[id]/edit/page.tsx
+++ b/src/app/dashboard/studies/[id]/edit/page.tsx
@@ -7,6 +7,7 @@ import { PageHeader } from "~/components/layout/page-header";
import { PageContent } from "~/components/layout/page-content";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "~/components/ui/card";
import { use } from "react";
+import { CardSkeleton } from "~/components/ui/skeleton";
export default function EditStudyPage({ params }: { params: Promise<{ id: string }> }) {
const router = useRouter();
@@ -29,7 +30,27 @@ export default function EditStudyPage({ params }: { params: Promise<{ id: string
}
if (isLoadingStudy) {
- return
Loading...
;
+ return (
+ <>
+
+
+
+
+ Study Details
+
+ Please wait while we load the study information.
+
+
+
+
+
+
+
+ >
+ );
}
if (!study) {
diff --git a/src/app/dashboard/studies/[id]/page.tsx b/src/app/dashboard/studies/[id]/page.tsx
index 855c11d..8025498 100644
--- a/src/app/dashboard/studies/[id]/page.tsx
+++ b/src/app/dashboard/studies/[id]/page.tsx
@@ -13,6 +13,7 @@ import { StudyParticipants } from "~/components/studies/study-participants";
import { StudyMembers } from "~/components/studies/study-members";
import { StudyMetadata } from "~/components/studies/study-metadata";
import { StudyActivity } from "~/components/studies/study-activity";
+import { StudyDetailsSkeleton } from "~/components/ui/skeleton";
export default function StudyPage({ params }: { params: Promise<{ id: string }> }) {
const router = useRouter();
@@ -24,7 +25,28 @@ export default function StudyPage({ params }: { params: Promise<{ id: string }>
const { data: study, isLoading: isLoadingStudy } = api.study.getById.useQuery({ id });
if (isLoadingStudy) {
- return Loading...
;
+ return (
+ <>
+
+
+
+
+ Overview
+ Participants
+ Members
+ Metadata
+ Activity
+
+
+
+
+
+
+ >
+ );
}
if (!study) {
diff --git a/src/app/dashboard/studies/[id]/participants/[participantId]/edit/page.tsx b/src/app/dashboard/studies/[id]/participants/[participantId]/edit/page.tsx
index 29b13ed..3771daf 100644
--- a/src/app/dashboard/studies/[id]/participants/[participantId]/edit/page.tsx
+++ b/src/app/dashboard/studies/[id]/participants/[participantId]/edit/page.tsx
@@ -9,6 +9,7 @@ import { ParticipantForm, type ParticipantFormValues } from "~/components/partic
import { use } from "react";
import { useToast } from "~/hooks/use-toast";
import { ROLES } from "~/lib/permissions/constants";
+import { CardSkeleton } from "~/components/ui/skeleton";
export default function EditParticipantPage({
params,
@@ -50,7 +51,27 @@ export default function EditParticipantPage({
}
if (isLoading) {
- return Loading...
;
+ return (
+ <>
+
+
+
+
+ Participant Details
+
+ Please wait while we load the participant information.
+
+
+
+
+
+
+
+ >
+ );
}
if (!study || !participant) {
diff --git a/src/app/dashboard/studies/page.tsx b/src/app/dashboard/studies/page.tsx
index 9386859..02c53c4 100644
--- a/src/app/dashboard/studies/page.tsx
+++ b/src/app/dashboard/studies/page.tsx
@@ -7,15 +7,12 @@ import { PageContent } from "~/components/layout/page-content";
import { Button } from "~/components/ui/button";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "~/components/ui/card";
import { Plus as PlusIcon } from "lucide-react";
+import { StudyListSkeleton } from "~/components/ui/skeleton";
export default function StudiesPage() {
const router = useRouter();
const { data: studies, isLoading } = api.study.getMyStudies.useQuery();
- if (isLoading) {
- return Loading...
;
- }
-
return (
<>
-
- {!studies || studies.length === 0 ? (
-
-
- No Studies
-
- You haven't created any studies yet. Click the button above to create your first study.
-
-
-
- ) : (
- studies.map((study) => (
+ {isLoading ? (
+
+ ) : !studies || studies.length === 0 ? (
+
+
+ No Studies
+
+ You haven't created any studies yet. Click the button above to create your first study.
+
+
+
+ ) : (
+
+ {studies.map((study) => (
- ))
- )}
-
+ ))}
+
+ )}
>
);
diff --git a/src/components/studies/study-participants.tsx b/src/components/studies/study-participants.tsx
index 2035d42..027d1ca 100644
--- a/src/components/studies/study-participants.tsx
+++ b/src/components/studies/study-participants.tsx
@@ -18,6 +18,7 @@ import { ROLES } from "~/lib/permissions/constants";
import { Switch } from "~/components/ui/switch";
import { Label } from "~/components/ui/label";
import { useState } from "react";
+import { TableSkeleton } from "~/components/ui/skeleton";
interface StudyParticipantsProps {
studyId: number;
@@ -38,7 +39,21 @@ export function StudyParticipants({ studyId, role }: StudyParticipantsProps) {
.includes(role.toLowerCase());
if (isLoading) {
- return Loading...
;
+ return (
+
+
+
+
+ Study Participants
+ Loading participants...
+
+
+
+
+
+
+
+ );
}
return (
diff --git a/src/components/ui/skeleton.tsx b/src/components/ui/skeleton.tsx
index cd75149..a2d9852 100644
--- a/src/components/ui/skeleton.tsx
+++ b/src/components/ui/skeleton.tsx
@@ -1,4 +1,5 @@
import { cn } from "~/lib/utils"
+import { Card, CardContent, CardHeader } from "~/components/ui/card"
function Skeleton({
className,
@@ -6,10 +7,132 @@ function Skeleton({
}: React.HTMLAttributes) {
return (
)
}
-export { Skeleton }
+function TableRowSkeleton() {
+ return (
+
+
+
+
+
+
+ )
+}
+
+function TableSkeleton() {
+ return (
+
+
+
+
+
+
+
+ {[...Array(5)].map((_, i) => (
+
+ ))}
+
+ )
+}
+
+function CardSkeleton() {
+ return (
+
+ )
+}
+
+function StudyListSkeleton() {
+ return (
+
+ {[...Array(3)].map((_, i) => (
+
+
+
+ ))}
+
+ )
+}
+
+function StudyDetailsSkeleton() {
+ return (
+
+ {/* Overview Card */}
+
+
+
+
+
+
+
+
+
+
+ {/* Stats Cards */}
+
+ {[...Array(3)].map((_, i) => (
+
+
+
+
+
+
+
+
+
+
+ ))}
+
+
+ {/* Activity Card */}
+
+
+
+
+
+
+
+ {[...Array(3)].map((_, i) => (
+
+ ))}
+
+
+
+
+ )
+}
+
+export {
+ Skeleton,
+ TableRowSkeleton,
+ TableSkeleton,
+ CardSkeleton,
+ StudyListSkeleton,
+ StudyDetailsSkeleton,
+}