141 lines
4.4 KiB
TypeScript
141 lines
4.4 KiB
TypeScript
"use client";
|
|
|
|
import SectionBottomActions from "@calcom/features/settings/SectionBottomActions";
|
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
|
import type { RouterOutputs } from "@calcom/trpc/react";
|
|
import { trpc } from "@calcom/trpc/react";
|
|
import { Alert } from "@calcom/ui/components/alert";
|
|
import { Button } from "@calcom/ui/components/button";
|
|
import { Form, TextAreaField, TextField } from "@calcom/ui/components/form";
|
|
import { SkeletonContainer, SkeletonText } from "@calcom/ui/components/skeleton";
|
|
import { showToast } from "@calcom/ui/components/toast";
|
|
import { useSession } from "next-auth/react";
|
|
import { useEffect } from "react";
|
|
import { useForm } from "react-hook-form";
|
|
|
|
type Team = RouterOutputs["viewer"]["teams"]["get"];
|
|
|
|
type FormValues = {
|
|
name: string;
|
|
slug: string;
|
|
bio: string;
|
|
logoUrl: string;
|
|
};
|
|
|
|
function isManager(team: Team | undefined, userId: number | undefined) {
|
|
if (!team || !userId) return false;
|
|
const member = team.members.find((m) => m.userId === userId);
|
|
return Boolean(member?.accepted && (member.role === "OWNER" || member.role === "ADMIN"));
|
|
}
|
|
|
|
export function TeamProfileView({ teamId }: { teamId: number }) {
|
|
const { t } = useLocale();
|
|
const session = useSession();
|
|
const utils = trpc.useUtils();
|
|
const teamQuery = trpc.viewer.teams.get.useQuery({ teamId });
|
|
const canManage = isManager(teamQuery.data, session.data?.user?.id);
|
|
|
|
const form = useForm<FormValues>({
|
|
defaultValues: { name: "", slug: "", bio: "", logoUrl: "" },
|
|
});
|
|
|
|
useEffect(() => {
|
|
if (!teamQuery.data) return;
|
|
form.reset({
|
|
name: teamQuery.data.name ?? "",
|
|
slug: teamQuery.data.slug ?? "",
|
|
bio: teamQuery.data.bio ?? "",
|
|
logoUrl: teamQuery.data.logoUrl ?? "",
|
|
});
|
|
}, [teamQuery.data, form]);
|
|
|
|
const updateMutation = trpc.viewer.teams.update.useMutation({
|
|
onSuccess: async () => {
|
|
await utils.viewer.teams.get.invalidate({ teamId });
|
|
await utils.viewer.teams.list.invalidate();
|
|
showToast(t("team_updated_successfully"), "success");
|
|
},
|
|
onError: (error) => showToast(error.message, "error"),
|
|
});
|
|
|
|
if (teamQuery.isPending) {
|
|
return (
|
|
<SkeletonContainer>
|
|
<div className="border-subtle stack-y-6 border-x px-4 py-8 sm:px-6">
|
|
<SkeletonText className="h-8 w-full" />
|
|
<SkeletonText className="h-8 w-full" />
|
|
<SkeletonText className="h-24 w-full" />
|
|
</div>
|
|
</SkeletonContainer>
|
|
);
|
|
}
|
|
|
|
if (teamQuery.error) {
|
|
return <Alert severity="error" title={teamQuery.error.message} />;
|
|
}
|
|
|
|
return (
|
|
<Form
|
|
form={form}
|
|
handleSubmit={(values) => {
|
|
if (!canManage) return;
|
|
updateMutation.mutate({
|
|
teamId,
|
|
name: values.name.trim(),
|
|
slug: values.slug.trim(),
|
|
bio: values.bio.trim() || null,
|
|
logoUrl: values.logoUrl.trim() || null,
|
|
});
|
|
}}>
|
|
{!canManage ? (
|
|
<Alert
|
|
severity="info"
|
|
className="mb-4"
|
|
title={t("you_are_a_member")}
|
|
message={t("only_admins_can_edit")}
|
|
/>
|
|
) : null}
|
|
<div className="border-subtle border-x px-4 py-6 sm:px-6">
|
|
<div className="space-y-4">
|
|
<TextField
|
|
{...form.register("name", { required: true, maxLength: 100 })}
|
|
label={t("team_name")}
|
|
disabled={!canManage}
|
|
data-testid="team-profile-name"
|
|
/>
|
|
<TextField
|
|
{...form.register("slug", { required: true, pattern: /^[a-z0-9-]+$/ })}
|
|
label={t("team_url")}
|
|
addOnLeading="/"
|
|
disabled={!canManage}
|
|
data-testid="team-profile-slug"
|
|
/>
|
|
<TextField
|
|
{...form.register("logoUrl")}
|
|
label={t("logo_url")}
|
|
placeholder="https://example.com/logo.png"
|
|
disabled={!canManage}
|
|
/>
|
|
<TextAreaField
|
|
{...form.register("bio", { maxLength: 500 })}
|
|
label={t("about")}
|
|
placeholder={t("team_description_placeholder")}
|
|
disabled={!canManage}
|
|
rows={4}
|
|
/>
|
|
</div>
|
|
</div>
|
|
<SectionBottomActions align="end">
|
|
<Button
|
|
type="submit"
|
|
color="primary"
|
|
loading={updateMutation.isPending}
|
|
disabled={!canManage || !form.formState.isDirty}
|
|
data-testid="team-profile-save">
|
|
{t("update")}
|
|
</Button>
|
|
</SectionBottomActions>
|
|
</Form>
|
|
);
|
|
}
|