mirror of
https://github.com/soconnor0919/hristudio.git
synced 2025-12-11 22:54:45 -05:00
chore(deps): Update dependencies and refactor API routes for improved error handling
- Updated various dependencies in package.json and pnpm-lock.yaml, including '@clerk/nextjs' to version 6.7.1 and several others for better performance and security. - Refactored API routes to use Promise.resolve for context parameters, enhancing reliability in asynchronous contexts. - Improved error handling in the dashboard and studies components, ensuring better user experience during data fetching. - Removed unused favicon.ico file to clean up the project structure. - Enhanced the dashboard components to utilize a new utility function for API URL fetching, promoting code reusability.
This commit is contained in:
@@ -187,15 +187,19 @@ export function Sidebar() {
|
||||
<div className="border-t border-[hsl(var(--sidebar-separator))]">
|
||||
<div className="flex items-center justify-between pt-4">
|
||||
<div className="flex items-center space-x-4">
|
||||
<UserButton />
|
||||
<div>
|
||||
<p className="text-sm font-medium text-[hsl(var(--sidebar-foreground))]">
|
||||
{user?.fullName ?? user?.username ?? 'User'}
|
||||
</p>
|
||||
<p className="text-xs text-[hsl(var(--sidebar-muted))]">
|
||||
{user?.primaryEmailAddress?.emailAddress ?? 'user@example.com'}
|
||||
</p>
|
||||
<div className="w-8 h-8">
|
||||
<UserButton afterSignOutUrl="/" />
|
||||
</div>
|
||||
{user && (
|
||||
<div className="min-w-0">
|
||||
<p className="text-sm font-medium text-[hsl(var(--sidebar-foreground))] truncate">
|
||||
{user.fullName ?? user.username ?? 'User'}
|
||||
</p>
|
||||
<p className="text-xs text-[hsl(var(--sidebar-muted))] truncate">
|
||||
{user.primaryEmailAddress?.emailAddress ?? 'user@example.com'}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use client';
|
||||
|
||||
import { useState, useEffect } from "react";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { Button } from "~/components/ui/button";
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "~/components/ui/card";
|
||||
import { useToast } from "~/hooks/use-toast";
|
||||
@@ -28,11 +28,7 @@ export function InvitationsTab({ studyId, permissions }: InvitationsTabProps) {
|
||||
const hasPermission = (permission: string) => permissions.includes(permission);
|
||||
const canManageRoles = hasPermission(PERMISSIONS.MANAGE_ROLES);
|
||||
|
||||
useEffect(() => {
|
||||
fetchInvitations();
|
||||
}, [studyId]);
|
||||
|
||||
const fetchInvitations = async () => {
|
||||
const fetchInvitations = useCallback(async () => {
|
||||
try {
|
||||
const response = await fetch(`/api/invitations?studyId=${studyId}`);
|
||||
if (!response.ok) throw new Error("Failed to fetch invitations");
|
||||
@@ -48,7 +44,12 @@ export function InvitationsTab({ studyId, permissions }: InvitationsTabProps) {
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
}, [studyId, toast]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchInvitations();
|
||||
}, [fetchInvitations]);
|
||||
|
||||
|
||||
const handleDeleteInvitation = async (invitationId: string) => {
|
||||
try {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use client';
|
||||
|
||||
import { useState, useEffect } from "react";
|
||||
import { useState, useEffect, useCallback } from "react";
|
||||
import { Button } from "~/components/ui/button";
|
||||
import {
|
||||
Dialog,
|
||||
@@ -41,14 +41,7 @@ export function InviteUserDialog({ studyId, onInviteSent }: InviteUserDialogProp
|
||||
const [roles, setRoles] = useState<Role[]>([]);
|
||||
const { toast } = useToast();
|
||||
|
||||
// Fetch available roles when dialog opens
|
||||
useEffect(() => {
|
||||
if (isOpen) {
|
||||
fetchRoles();
|
||||
}
|
||||
}, [isOpen]);
|
||||
|
||||
const fetchRoles = async () => {
|
||||
const fetchRoles = useCallback(async () => {
|
||||
try {
|
||||
const response = await fetch("/api/roles");
|
||||
if (!response.ok) {
|
||||
@@ -67,7 +60,12 @@ export function InviteUserDialog({ studyId, onInviteSent }: InviteUserDialogProp
|
||||
variant: "destructive",
|
||||
});
|
||||
}
|
||||
};
|
||||
}, [toast]);
|
||||
|
||||
// Fetch available roles when dialog opens
|
||||
useEffect(() => {
|
||||
fetchRoles();
|
||||
}, [fetchRoles]);
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use client';
|
||||
|
||||
import { useState, useEffect } from "react";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { PlusIcon, Trash2Icon } from "lucide-react";
|
||||
import { Button } from "~/components/ui/button";
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "~/components/ui/card";
|
||||
@@ -43,11 +43,7 @@ export function ParticipantsTab({ studyId, permissions }: ParticipantsTabProps)
|
||||
const canDeleteParticipant = hasPermission(PERMISSIONS.DELETE_PARTICIPANT);
|
||||
const canViewNames = hasPermission(PERMISSIONS.VIEW_PARTICIPANT_NAMES);
|
||||
|
||||
useEffect(() => {
|
||||
fetchParticipants();
|
||||
}, [studyId]);
|
||||
|
||||
const fetchParticipants = async () => {
|
||||
const fetchParticipants = useCallback(async () => {
|
||||
try {
|
||||
const response = await fetch(`/api/studies/${studyId}/participants`);
|
||||
if (!response.ok) throw new Error("Failed to fetch participants");
|
||||
@@ -63,7 +59,11 @@ export function ParticipantsTab({ studyId, permissions }: ParticipantsTabProps)
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
}, [toast, studyId]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchParticipants();
|
||||
}, [fetchParticipants]);
|
||||
|
||||
const createParticipant = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
|
||||
@@ -72,7 +72,7 @@ export function SettingsTab({ study }: SettingsTabProps) {
|
||||
<Card>
|
||||
<CardContent className="py-8">
|
||||
<p className="text-center text-muted-foreground">
|
||||
You don't have permission to edit this study.
|
||||
You don't have permission to edit this study.
|
||||
</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use client';
|
||||
|
||||
import { useState, useEffect } from "react";
|
||||
import { useState, useEffect, useCallback } from "react";
|
||||
import { UserAvatar } from "~/components/user-avatar";
|
||||
import { Button } from "~/components/ui/button";
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "~/components/ui/card";
|
||||
@@ -38,8 +38,7 @@ import {
|
||||
interface User {
|
||||
id: string;
|
||||
email: string;
|
||||
firstName: string | null;
|
||||
lastName: string | null;
|
||||
name: string | null;
|
||||
roles: Array<{ id: number; name: string }>;
|
||||
}
|
||||
|
||||
@@ -72,23 +71,7 @@ export function UsersTab({ studyId, permissions }: UsersTabProps) {
|
||||
const hasPermission = (permission: string) => permissions.includes(permission);
|
||||
const canManageRoles = hasPermission(PERMISSIONS.MANAGE_ROLES);
|
||||
|
||||
useEffect(() => {
|
||||
fetchData();
|
||||
}, [studyId]);
|
||||
|
||||
const fetchData = async () => {
|
||||
try {
|
||||
await Promise.all([
|
||||
fetchUsers(),
|
||||
fetchInvitations(),
|
||||
fetchRoles(),
|
||||
]);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const fetchUsers = async () => {
|
||||
const fetchUsers = useCallback(async () => {
|
||||
try {
|
||||
const response = await fetch(`/api/studies/${studyId}/users`);
|
||||
if (!response.ok) throw new Error("Failed to fetch users");
|
||||
@@ -102,9 +85,9 @@ export function UsersTab({ studyId, permissions }: UsersTabProps) {
|
||||
variant: "destructive",
|
||||
});
|
||||
}
|
||||
};
|
||||
}, [studyId, toast]);
|
||||
|
||||
const fetchInvitations = async () => {
|
||||
const fetchInvitations = useCallback(async () => {
|
||||
try {
|
||||
const response = await fetch(`/api/invitations?studyId=${studyId}`);
|
||||
if (!response.ok) throw new Error("Failed to fetch invitations");
|
||||
@@ -118,9 +101,9 @@ export function UsersTab({ studyId, permissions }: UsersTabProps) {
|
||||
variant: "destructive",
|
||||
});
|
||||
}
|
||||
};
|
||||
}, [studyId, toast]);
|
||||
|
||||
const fetchRoles = async () => {
|
||||
const fetchRoles = useCallback(async () => {
|
||||
try {
|
||||
const response = await fetch("/api/roles");
|
||||
if (!response.ok) throw new Error("Failed to fetch roles");
|
||||
@@ -136,7 +119,24 @@ export function UsersTab({ studyId, permissions }: UsersTabProps) {
|
||||
variant: "destructive",
|
||||
});
|
||||
}
|
||||
};
|
||||
}, [toast]);
|
||||
|
||||
const fetchData = useCallback(async () => {
|
||||
setIsLoading(true);
|
||||
try {
|
||||
await Promise.all([
|
||||
fetchUsers(),
|
||||
fetchInvitations(),
|
||||
fetchRoles(),
|
||||
]);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}, [fetchUsers, fetchInvitations, fetchRoles]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchData();
|
||||
}, [fetchData]);
|
||||
|
||||
const handleRoleChange = async (userId: string, newRoleId: string) => {
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user