Files
projectsend/resources/js/components/group-form.tsx
ignacionelson 6e47d76ba6 ProjectSend 2.0.0
Client file sharing, rebuilt from the ground up: a private area per
client, resumable uploads, folders, groups and categories, sharing with
expiry dates and download limits, comments, file versions, an activity
log, a REST API, and sixteen languages.

This repository begins here. ProjectSend 2 was developed privately, and
that development history is not published — the previous generation
remains available, with its own history, at projectsend/legacy.

Free software under the GNU General Public License v2, or (at your
option) any later version.
2026-08-14 01:38:12 -03:00

82 lines
3.4 KiB
TypeScript

import { useState } from 'react';
import InputError from '@/components/input-error';
import { Checkbox } from '@/components/ui/checkbox';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { useTranslation } from '@/hooks/use-translation';
import { slugify } from '@/lib/utils';
interface GroupFormProps {
name: string;
slug: string;
description: string;
isPublic: boolean;
onChange: (field: 'name' | 'slug' | 'description' | 'public', value: string | boolean) => void;
errors: Partial<Record<string, string>>;
}
export function GroupForm({ name, slug, description, isPublic, onChange, errors }: GroupFormProps) {
const { t } = useTranslation();
// Auto-fill the slug from the name until the user edits it directly
// (an already-populated slug, e.g. when editing, counts as touched
// so we never clobber a deliberate value).
const [slugTouched, setSlugTouched] = useState(slug !== '');
return (
<div className="grid max-w-md gap-6">
<div className="grid gap-2">
<Label htmlFor="name">{t('Name')}</Label>
<Input
id="name"
value={name}
onChange={(e) => onChange('name', e.target.value)}
onBlur={() => {
if (!slugTouched) onChange('slug', slugify(name));
}}
required
/>
<InputError message={errors.name} />
</div>
<div className="grid gap-2">
<Label htmlFor="description">{t('Description')}</Label>
<Input id="description" value={description} onChange={(e) => onChange('description', e.target.value)} />
<InputError message={errors.description} />
</div>
<div className="grid gap-2">
<div className="flex items-start gap-2">
<Checkbox id="public" checked={isPublic} onCheckedChange={(checked) => onChange('public', checked === true)} />
<div className="grid gap-1">
<Label htmlFor="public" className="font-normal">
{t('Public group')}
</Label>
<p className="text-muted-foreground text-sm">
{t('The files of a public group can be browsed by anyone with the link, without logging in.')}
</p>
</div>
</div>
<InputError message={errors.public} />
{isPublic && (
<div className="mt-2 grid gap-2 pl-6">
<Label htmlFor="slug">{t('URL slug')}</Label>
<Input
id="slug"
value={slug}
onChange={(e) => {
setSlugTouched(true);
onChange('slug', e.target.value);
}}
required
/>
<p className="text-muted-foreground text-sm">{t('Used in the public group URL when this group is public.')}</p>
<InputError message={errors.slug} />
</div>
)}
</div>
</div>
);
}