because I got bored of customising my CV for every job
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

refactor(client): update organization components

+153 -69
+45 -5
apps/client/src/features/organizations/components/MembersTableBody.tsx
··· 1 - import type { MeWithOrganizationsQuery } from "@/generated/graphql"; 2 - import { TableBody } from "@/ui/Table"; 1 + import { TableBody } from "@cv/ui"; 3 2 import { OrganizationMemberRow } from "./OrganizationMemberRow"; 4 3 5 - type Organization = NonNullable< 6 - NonNullable<MeWithOrganizationsQuery["me"]>["organizations"] 7 - >[0]; 4 + type Organization = { 5 + id: string; 6 + name: string; 7 + description: string | null; 8 + users: Array<{ 9 + id: string; 10 + joinedAt: string; 11 + role: { 12 + id: string; 13 + name: string; 14 + description: string | null; 15 + color: string; 16 + }; 17 + user: { 18 + id: string; 19 + name: string; 20 + email: string; 21 + createdAt: string; 22 + experience: Array<{ 23 + id: string; 24 + startDate: string; 25 + endDate: string | null; 26 + description: string | null; 27 + company: { 28 + id: string; 29 + name: string; 30 + website: string | null; 31 + }; 32 + role: { 33 + id: string; 34 + name: string; 35 + }; 36 + level: { 37 + id: string; 38 + name: string; 39 + }; 40 + skills: Array<{ 41 + id: string; 42 + name: string; 43 + }>; 44 + }>; 45 + }; 46 + }>; 47 + }; 8 48 9 49 interface MembersTableBodyProps { 10 50 organization: Organization;
+1 -1
apps/client/src/features/organizations/components/MembersTableHeader.tsx
··· 1 - import { TableHeader, TableHeaderCell, TableRow } from "@/ui/Table"; 1 + import { TableHeader, TableHeaderCell, TableRow } from "@cv/ui"; 2 2 3 3 export const MembersTableHeader = () => { 4 4 return (
+61 -43
apps/client/src/features/organizations/components/OrganizationMemberRow.tsx
··· 1 - import type { MeWithOrganizationsQuery } from "@/generated/graphql"; 2 - import Badge, { type CatppuccinColor } from "@/ui/Badge"; 3 - import { TableCell, TableRow } from "@/ui/Table"; 1 + import { Badge, TableCell, TableRow } from "@cv/ui"; 2 + import type { OrganizationMembersQuery } from "@/generated/graphql"; 4 3 5 - type OrganizationMember = NonNullable< 6 - NonNullable<MeWithOrganizationsQuery["me"]>["organizations"] 7 - >[0]["users"][0]; 4 + type BadgeColor = 5 + | "ctp-red" 6 + | "ctp-orange" 7 + | "ctp-yellow" 8 + | "ctp-green" 9 + | "ctp-teal" 10 + | "ctp-sky" 11 + | "ctp-sapphire" 12 + | "ctp-blue" 13 + | "ctp-lavender" 14 + | "ctp-mauve" 15 + | "ctp-pink" 16 + | "ctp-maroon" 17 + | "ctp-peach" 18 + | "ctp-rosewater" 19 + | "ctp-gray"; 20 + 21 + // Use the actual GraphQL type for the member node 22 + type MemberNode = NonNullable< 23 + NonNullable< 24 + OrganizationMembersQuery["organization"] 25 + >["memberships"]["edges"][0]["node"] 26 + >; 8 27 9 28 interface OrganizationMemberRowProps { 10 - member: OrganizationMember; 29 + member: MemberNode; 11 30 } 12 31 13 32 export const OrganizationMemberRow = ({ 14 - member, 33 + member: { user, role, joinedAt }, 15 34 }: OrganizationMemberRowProps) => { 16 - const hasExperience = 17 - member.user.experience && member.user.experience.length > 0; 18 - const currentPosition = hasExperience ? member.user.experience?.[0] : null; 35 + const experience = user.experience ?? []; 36 + const currentPosition = experience[0]; 19 37 20 38 return ( 21 39 <TableRow> 22 40 <TableCell> 23 41 <div> 24 - <div className="text-sm font-medium text-ctp-text"> 25 - {member.user.name} 26 - </div> 27 - <div className="text-sm text-ctp-subtext0">{member.user.email}</div> 42 + <div className="text-sm font-medium text-ctp-text">{user.name}</div> 43 + <div className="text-sm text-ctp-subtext0">{user.email}</div> 28 44 </div> 29 45 </TableCell> 30 46 31 47 <TableCell> 32 48 <div className="flex items-center"> 33 - {member.role ? ( 34 - <Badge color={member.role.color as CatppuccinColor}> 35 - {member.role.name} 36 - </Badge> 49 + {role ? ( 50 + <Badge color={role.color as BadgeColor}>{role.name}</Badge> 37 51 ) : ( 38 52 <span className="text-ctp-subtext0">No role</span> 39 53 )} ··· 41 55 </TableCell> 42 56 43 57 <TableCell> 44 - {currentPosition ? ( 45 - <div> 46 - <div className="font-medium">{currentPosition.company.name}</div> 47 - <div className="text-ctp-subtext0"> 48 - {currentPosition.role.name} • {currentPosition.level.name} 58 + <div> 59 + {currentPosition ? ( 60 + <div> 61 + <div className="font-medium">{currentPosition.company.name}</div> 62 + <div className="text-ctp-subtext0"> 63 + {currentPosition.role.name} • {currentPosition.level.name} 64 + </div> 49 65 </div> 50 - </div> 51 - ) : ( 52 - <span className="text-ctp-subtext0">No experience data</span> 53 - )} 66 + ) : ( 67 + <span className="text-ctp-subtext0">No experience data</span> 68 + )} 69 + </div> 54 70 </TableCell> 55 71 56 72 <TableCell> 57 - {hasExperience ? ( 58 - <div> 59 - <div className="font-medium"> 60 - {member.user.experience?.length} position 61 - {member.user.experience?.length !== 1 ? "s" : ""} 62 - </div> 63 - <div className="text-ctp-subtext0"> 64 - {member.user.experience && member.user.experience.length > 1 && ( 65 - <span>+{member.user.experience.length - 1} more</span> 66 - )} 73 + <div> 74 + {currentPosition ? ( 75 + <div> 76 + <div className="font-medium"> 77 + {experience?.length} position 78 + {experience?.length !== 1 ? "s" : ""} 79 + </div> 80 + <div className="text-ctp-subtext0"> 81 + {experience.length > 1 && ( 82 + <span>+{experience.length - 1} more</span> 83 + )} 84 + </div> 67 85 </div> 68 - </div> 69 - ) : ( 70 - <span className="text-ctp-subtext0">No experience</span> 71 - )} 86 + ) : ( 87 + <span className="text-ctp-subtext0">No experience</span> 88 + )} 89 + </div> 72 90 </TableCell> 73 91 74 92 <TableCell className="text-ctp-subtext0"> 75 - {new Date(member.joinedAt).toLocaleDateString()} 93 + <div>{new Date(joinedAt).toLocaleDateString()}</div> 76 94 </TableCell> 77 95 </TableRow> 78 96 );
+46 -20
apps/client/src/features/organizations/components/OrganizationMembersTable.tsx
··· 1 - import type { MeWithOrganizationsQuery } from "@/generated/graphql"; 2 - import { Table } from "@/ui/Table"; 1 + import { Table } from "@cv/ui"; 3 2 import { MembersTableBody } from "./MembersTableBody"; 4 3 import { MembersTableHeader } from "./MembersTableHeader"; 5 4 6 - type Organization = NonNullable< 7 - NonNullable<MeWithOrganizationsQuery["me"]>["organizations"] 8 - >[0]; 5 + type Organization = { 6 + id: string; 7 + name: string; 8 + description: string | null; 9 + users: Array<{ 10 + id: string; 11 + joinedAt: string; 12 + role: { 13 + id: string; 14 + name: string; 15 + description: string | null; 16 + color: string; 17 + }; 18 + user: { 19 + id: string; 20 + name: string; 21 + email: string; 22 + createdAt: string; 23 + experience: Array<{ 24 + id: string; 25 + startDate: string; 26 + endDate: string | null; 27 + description: string | null; 28 + company: { 29 + id: string; 30 + name: string; 31 + website: string | null; 32 + }; 33 + role: { 34 + id: string; 35 + name: string; 36 + }; 37 + level: { 38 + id: string; 39 + name: string; 40 + }; 41 + skills: Array<{ 42 + id: string; 43 + name: string; 44 + }>; 45 + }>; 46 + }; 47 + }>; 48 + }; 9 49 10 50 interface OrganizationMembersTableProps { 11 51 organization: Organization; ··· 30 70 } 31 71 32 72 return ( 33 - <div className="bg-ctp-surface0 rounded-lg border border-ctp-surface1 p-6"> 34 - <div className="mb-6"> 35 - <h2 className="text-xl font-semibold text-ctp-text"> 36 - {organization.name} Members 37 - </h2> 38 - {organization.description && ( 39 - <p className="mt-1 text-sm text-ctp-subtext0"> 40 - {organization.description} 41 - </p> 42 - )} 43 - <div className="mt-2 text-sm text-ctp-subtext0"> 44 - {members.length} member{members.length !== 1 ? "s" : ""} found 45 - </div> 46 - </div> 47 - 73 + <div> 48 74 <Table> 49 75 <MembersTableHeader /> 50 76 <MembersTableBody organization={organization} />