feat(organization): add logo support for organizations

This commit is contained in:
Mauricio Siu
2025-02-25 23:28:19 -06:00
parent d3c59ff8af
commit 7d77e14319
4 changed files with 37 additions and 4 deletions

View File

@@ -35,14 +35,16 @@ export function AddOrganization({ organizationId }: Props) {
: api.organization.create.useMutation(); : api.organization.create.useMutation();
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const [name, setName] = useState(""); const [name, setName] = useState("");
const [logo, setLogo] = useState("");
useEffect(() => { useEffect(() => {
if (organization) { if (organization) {
setName(organization.name); setName(organization.name);
setLogo(organization.logo || "");
} }
}, [organization]); }, [organization]);
const handleSubmit = async () => { const handleSubmit = async () => {
await mutateAsync({ name, organizationId: organizationId ?? "" }) await mutateAsync({ name, logo, organizationId: organizationId ?? "" })
.then(() => { .then(() => {
setOpen(false); setOpen(false);
toast.success( toast.success(
@@ -91,7 +93,7 @@ export function AddOrganization({ organizationId }: Props) {
</DialogTitle> </DialogTitle>
<DialogDescription> <DialogDescription>
{organizationId {organizationId
? "Update the organization name" ? "Update the organization name and logo"
: "Create a new organization to manage your projects."} : "Create a new organization to manage your projects."}
</DialogDescription> </DialogDescription>
</DialogHeader> </DialogHeader>
@@ -107,6 +109,18 @@ export function AddOrganization({ organizationId }: Props) {
className="col-span-3" className="col-span-3"
/> />
</div> </div>
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="logo" className="text-right">
Logo URL
</Label>
<Input
id="logo"
value={logo}
onChange={(e) => setLogo(e.target.value)}
placeholder="https://example.com/logo.png"
className="col-span-3"
/>
</div>
</div> </div>
<DialogFooter> <DialogFooter>
<Button type="submit" onClick={handleSubmit} isLoading={isLoading}> <Button type="submit" onClick={handleSubmit} isLoading={isLoading}>

View File

@@ -562,6 +562,7 @@ function SidebarLogo() {
"transition-all", "transition-all",
state === "collapsed" ? "size-4" : "size-5", state === "collapsed" ? "size-4" : "size-5",
)} )}
logoUrl={activeOrganization?.logo}
/> />
</div> </div>
<div <div
@@ -607,6 +608,7 @@ function SidebarLogo() {
"transition-all", "transition-all",
state === "collapsed" ? "size-6" : "size-10", state === "collapsed" ? "size-6" : "size-10",
)} )}
logoUrl={org.logo ?? undefined}
/> />
</div> </div>
</DropdownMenuItem> </DropdownMenuItem>

View File

@@ -1,8 +1,20 @@
interface Props { interface Props {
className?: string; className?: string;
logoUrl?: string;
} }
export const Logo = ({ className = "size-14" }: Props) => { export const Logo = ({ className = "size-14", logoUrl }: Props) => {
if (logoUrl) {
return (
<img
src={logoUrl}
alt="Organization Logo"
className={className}
style={{ objectFit: "contain" }}
/>
);
}
return ( return (
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"

View File

@@ -11,6 +11,7 @@ export const organizationRouter = createTRPCRouter({
.input( .input(
z.object({ z.object({
name: z.string(), name: z.string(),
logo: z.string().optional(),
}), }),
) )
.mutation(async ({ ctx, input }) => { .mutation(async ({ ctx, input }) => {
@@ -81,6 +82,7 @@ export const organizationRouter = createTRPCRouter({
z.object({ z.object({
organizationId: z.string(), organizationId: z.string(),
name: z.string(), name: z.string(),
logo: z.string().optional(),
}), }),
) )
.mutation(async ({ ctx, input }) => { .mutation(async ({ ctx, input }) => {
@@ -92,7 +94,10 @@ export const organizationRouter = createTRPCRouter({
} }
const result = await db const result = await db
.update(organization) .update(organization)
.set({ name: input.name }) .set({
name: input.name,
logo: input.logo,
})
.where(eq(organization.id, input.organizationId)) .where(eq(organization.id, input.organizationId))
.returning(); .returning();
return result[0]; return result[0];