😎
【Convex】NextJs14 と Convex【#8Organization List】
【#8Organization List】
YouTube: https://youtu.be/I0EJuZORXGM
今回はOrganizationのリストを実装します。
my-app/(main)/_components/sidebar.tsx
"use client";
import { List } from "./list";
import { NewOrgButton } from "./new-org-button";
export const Sidebar = () => {
return (
<div className="w-[60px] h-full fixed z-10 bg-slate-700 p-2 flex flex-col gap-y-3">
<List />
<NewOrgButton />
</div>
);
};
my-app/(main)/_components/org-list.tsx
import { useOrganizationList } from "@clerk/nextjs";
import { OrgListItem } from "./org-list-item";
export const OrgList = () => {
const { userMemberships } = useOrganizationList({
userMemberships: {
infinite: true,
},
});
if (!userMemberships || !userMemberships.data) return null;
return (
<ul className="space-y-3">
{userMemberships.data.map((org) => (
<OrgListItem
key={org.organization.id}
id={org.organization.id}
name={org.organization.name}
imageUrl={org.organization.imageUrl}
/>
))}
</ul>
);
};
my-app/(main)/_components/org-list-item.tsx
import Image from "next/image";
import { useOrganization, useOrganizationList } from "@clerk/nextjs";
import { cn } from "@/lib/utils";
interface Props {
id: string;
name: string;
imageUrl: string;
}
export const OrgListItem = ({ id, name, imageUrl }: Props) => {
const { organization } = useOrganization();
const { setActive } = useOrganizationList();
const isActive = organization?.id === id;
const onClick = () => {
if (!setActive) return;
setActive({ organization: id });
};
return (
<li className="aspect-square relative">
<Image
src={imageUrl}
alt={name}
fill
onClick={onClick}
className={cn(
"rounded-md cursor-pointer opacity-75 hover:opacity-100 transition",
isActive && "opacity-100"
)}
/>
</li>
);
};
next.config.mjs
/** @type {import('next').NextConfig} */
const nextConfig = {
images: {
remotePatterns: [
{
protocol: "https",
hostname: "img.clerk.com",
},
],
},
};
export default nextConfig;
Discussion