Merge Tag v0.2.12

This commit is contained in:
2025-05-19 12:56:21 +02:00
48 changed files with 3626 additions and 469 deletions

View File

@@ -9,14 +9,15 @@ import { cn } from '@/lib/utils';
import { Description } from '@radix-ui/react-dialog';
import { useAtom } from 'jotai';
import { Crown, Plus, User as UserIcon, UserRoundPen } from 'lucide-react';
import { useTranslations } from 'next-intl';
import { useState } from 'react';
import PasswordEntryForm from './PasswordEntryForm';
import UserForm from './UserForm';
import { Avatar, AvatarFallback, AvatarImage } from './ui/avatar';
import { Dialog, DialogContent, DialogHeader, DialogTitle } from './ui/dialog';
function UserCard({
user,
function UserCard({
user,
onSelect,
onEdit,
showEdit,
@@ -38,9 +39,9 @@ function UserCard({
)}
>
<Avatar className="h-16 w-16">
<AvatarImage
<AvatarImage
src={user.avatarPath && `/api/avatars/${user.avatarPath.split('/').pop()}`}
alt={user.username}
alt={user.username}
/>
<AvatarFallback>
<UserIcon className="h-8 w-8" />
@@ -67,6 +68,7 @@ function UserCard({
}
function AddUserButton({ onClick }: { onClick: () => void }) {
const t = useTranslations('UserSelectModal');
return (
<button
onClick={onClick}
@@ -77,7 +79,7 @@ function AddUserButton({ onClick }: { onClick: () => void }) {
<Plus className="h-8 w-8" />
</AvatarFallback>
</Avatar>
<span className="text-sm font-medium">Add User</span>
<span className="text-sm font-medium">{t('addUserButton')}</span>
</button>
);
}
@@ -87,13 +89,13 @@ function UserSelectionView({
currentUser,
onUserSelect,
onEditUser,
onCreateUser
onCreateUser,
}: {
users: User[],
currentUser?: SafeUser,
onUserSelect: (userId: string) => void,
onEditUser: (userId: string) => void,
onCreateUser: () => void
onCreateUser: () => void,
}) {
return (
<div className="grid grid-cols-3 gap-4 p-2 max-h-80 overflow-y-auto">
@@ -108,20 +110,21 @@ function UserSelectionView({
showEdit={!!currentUser?.isAdmin}
isCurrentUser={false}
/>
))}
))}
{currentUser?.isAdmin && <AddUserButton onClick={onCreateUser} />}
</div>
);
}
export default function UserSelectModal({ onClose }: { onClose: () => void }) {
const t = useTranslations('UserSelectModal');
const [selectedUser, setSelectedUser] = useState<string>();
const [isCreating, setIsCreating] = useState(false);
const [isEditing, setIsEditing] = useState(false);
const [error, setError] = useState('');
const [usersData] = useAtom(usersAtom);
const users = usersData.users;
const {currentUser} = useHelpers();
const { currentUser } = useHelpers();
const handleUserSelect = (userId: string) => {
setSelectedUser(userId);
@@ -156,7 +159,7 @@ const {currentUser} = useHelpers();
<DialogContent className="sm:max-w-md">
<Description></Description>
<DialogHeader>
<DialogTitle>{isCreating ? 'Create New User' : 'Select User'}</DialogTitle>
<DialogTitle>{isCreating ? t('createNewUserTitle') : t('selectUserTitle')}</DialogTitle>
</DialogHeader>
<div className="flex flex-col gap-4">
@@ -184,19 +187,19 @@ const {currentUser} = useHelpers();
const user = users.find(u => u.id === selectedUser);
if (!user) throw new Error("User not found");
await signIn(user.username, password);
setError('');
onClose();
toast({
title: "Signed in successfully",
description: `Welcome back, ${user.username}!`,
title: t('signInSuccessTitle'),
description: t('signInSuccessDescription', { username: user.username }),
variant: "default"
});
setTimeout(() => window.location.reload(), 300);
} catch (err) {
setError('invalid password');
setError(t('errorInvalidPassword'));
throw err;
}
}}