Skip to content

Commit

Permalink
refactor: user can join upto 3 teams only. backend
Browse files Browse the repository at this point in the history
  • Loading branch information
Amama-Fatima committed Jun 22, 2024
1 parent d91fb4e commit 9021263
Show file tree
Hide file tree
Showing 7 changed files with 122 additions and 23 deletions.
19 changes: 19 additions & 0 deletions src/app/api/invitations/invitation/[inv_id]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,16 @@ export async function PUT(
{ params }: { params: { inv_id: string } }
) {
//get id from api url

const inv_id = params.inv_id;
const body = await req.json(); //body will contain status

const serverSupabase = createSupabaseServerClient();

const {
data: { user: serverUser },
} = await serverSupabase.auth.getUser();

const { data: invitationData, error } = await serverSupabase
.from('invitations')
.update({ inv_status: body.status })
Expand All @@ -23,6 +28,20 @@ export async function PUT(
{ status: 500 }
);
}
//also update teams_joined in profiles table
if (body.status === 'ACCEPTED') {
const { error: profileError } = await serverSupabase
.from('profiles')
.update({ teams_joined: body.teams_joined })
.eq('id', serverUser?.id);

if (profileError) {
return NextResponse.json(
{ success: false, error: profileError.message },
{ status: 500 }
);
}
}

return NextResponse.json(
{ success: true, data: invitationData },
Expand Down
58 changes: 45 additions & 13 deletions src/app/api/teams/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import { createSupabaseServerClient } from '@/lib/supabase/server-clients';
export async function POST(req: Request) {
try {
const body = await req.json();
const teamData = teamFormSchema.parse(body);
const { teamData } = body;
const teamDataParsed = teamFormSchema.parse(teamData);
const serverSupabase = createSupabaseServerClient();

//get current user id
Expand All @@ -30,9 +31,9 @@ export async function POST(req: Request) {
}

// eslint-disable-next-line unused-imports/no-unused-vars
const { team_head, members, ...team } = teamData;
const { team_head, members, ...team } = teamDataParsed;
if (user_id) {
const teamData: teamSchemaType = {
const teamDataParsed: teamSchemaType = {
...team,
team_head: user_id,
team_id: v4(),
Expand All @@ -45,33 +46,64 @@ export async function POST(req: Request) {
//now add members to team-members table. Also add current user to team-members table and set isteamHead to true for him
const membersData = members.map((member) => ({
member_id: member,
team_id: teamData.team_id,
team_id: teamDataParsed.team_id,
isTeamHead: member === user_id,
}));

const { error: teamMembersError } = await serverSupabase
.from('teams-members')
.insert(membersData);
//map over membersData and get their teams_joined from profiles table and update it
const updateDataArray = await Promise.all(
membersData.map(async (member) => {
const { data: profileData, error } = await serverSupabase
.from('profiles')
.select('teams_joined')
.eq('id', member.member_id);
if (error) {
throw new Error(error.message);
}
return {
teams_joined: profileData[0].teams_joined + 1,
user_id: member.member_id,
requester_id: user_id,
};
})
);

if (teamMembersError) {
throw new Error('Failed to create team');
}
await Promise.all(
updateDataArray.map(async (updateData) => {
const { error } = await serverSupabase.rpc('update_teams_joined', {
requester_id: updateData.requester_id,
user_id: updateData.user_id,
updated_teams_joined: updateData.teams_joined,
});
if (error) {
throw new Error(error.message);
}
})
);

//now insert team data
const { error: teamError } = await serverSupabase
.from('teams')
.insert([{ ...teamData }]);
.insert([{ ...teamDataParsed }]);
if (teamError) {
throw new Error(teamError.message);
}

const { error: teamMembersError } = await serverSupabase
.from('teams-members')
.insert(membersData);

if (teamMembersError) {
throw new Error('Failed to create team');
}

return new Response(JSON.stringify(teamData), { status: 200 });
return new Response(JSON.stringify(teamDataParsed), { status: 200 });
}
} catch (error: unknown) {
if (error instanceof z.ZodError) {
return new Response(JSON.stringify(error.issues), { status: 422 });
} else if (error instanceof Error) {
return new Response(error.message, { status: 500 });
return new Response(error.message, { status: 404 });
} else {
return new Response(null, { status: 500 });
}
Expand Down
11 changes: 11 additions & 0 deletions src/app/api/teams/team/[team_id]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ export async function PUT(
throw new Error('User not found');
}
const { team_id } = params;
const teams_joined = await req.json();
const newMemberData = {
team_id,
member_id: user_id,
Expand All @@ -77,6 +78,16 @@ export async function PUT(
if (error) {
throw new Error(error.message);
}

//also increase teams_joined in profiles by 1
const { error: profileError } = await serverSupabase
.from('profiles')
.update({ teams_joined: teams_joined.teams_joined })
.eq('id', user_id);
if (profileError) {
throw new Error(profileError.message);
}

return new Response(JSON.stringify(data), { status: 201 });
} catch (error: unknown) {
if (error instanceof Error) {
Expand Down
10 changes: 7 additions & 3 deletions src/components/forms/create-team-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,12 @@ export default function CreateTeamForm({ user }: CreateTeamFormProps) {
const [selectedMembers, setSelectedMembers] = useState<Set<string>>(
new Set()
);
const { fetchTeamsJoined, canJoinMoreTeams, increaseTeamsJoined } =
useCanJoinTeamStore();
const {
fetchTeamsJoined,
canJoinMoreTeams,
increaseTeamsJoined,
teamsJoined,
} = useCanJoinTeamStore();

useEffect(() => {
fetchTeamsJoined(user.id);
Expand Down Expand Up @@ -99,7 +103,7 @@ export default function CreateTeamForm({ user }: CreateTeamFormProps) {
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(teamData),
body: JSON.stringify({ teamData, teams_joined: teamsJoined + 1 }),
});
if (!response.ok) {
throw new Error('Failed to create team');
Expand Down
18 changes: 13 additions & 5 deletions src/components/pending-invitations.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,12 @@ const Invitations = () => {
const userId = user?.id;

const [isLoading, setIsLoading] = useState(false);
const { fetchTeamsJoined, canJoinMoreTeams, increaseTeamsJoined } =
useCanJoinTeamStore();
const {
fetchTeamsJoined,
canJoinMoreTeams,
increaseTeamsJoined,
teamsJoined,
} = useCanJoinTeamStore();

useEffect(() => {
fetchTeamsJoined(userId);
Expand Down Expand Up @@ -63,7 +67,7 @@ const Invitations = () => {
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ status: status }),
body: JSON.stringify({ status: status, teams_joined: teamsJoined + 1 }),
});

if (response.status !== 200) {
Expand Down Expand Up @@ -141,12 +145,16 @@ const Invitations = () => {
{pendingInvitationsLoading ? (
<div className='flex justify-center items-center mt-32'>
<Icons.spinner
className=' size-20 animate-spin text-primary-foreground rounded-md p-1'
className='size-20 animate-spin text-primary-foreground rounded-md p-1'
aria-hidden='true'
/>
</div>
) : pendingInvitationsData.data?.length === 0 ? (
<h1>No pending invitations</h1>
<div className='mt-6 rounded-md border border-muted-foreground p-2'>
<p className='text-muted-foreground text-sm'>
No pending invitations
</p>
</div>
) : (
<div className='px-2 py-4 '>
<div className='flex flex-col border-2 border-muted-foreground rounded-md'>
Expand Down
9 changes: 7 additions & 2 deletions src/components/team-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,12 @@ export default function TeamCard({
}: TeamCardProps) {
const [isLoading, setIsLoading] = useState(false);
const [isUserAlreadyInTeam, setIsUserAlreadyInTeam] = useState(false);
const { fetchTeamsJoined, canJoinMoreTeams, increaseTeamsJoined } =
useCanJoinTeamStore();
const {
fetchTeamsJoined,
canJoinMoreTeams,
increaseTeamsJoined,
teamsJoined,
} = useCanJoinTeamStore();

useEffect(() => {
fetchTeamsJoined(userId);
Expand All @@ -58,6 +62,7 @@ export default function TeamCard({
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ teams_joined: teamsJoined + 1 }),
});
if (!response.ok) {
throw new Error('Network response was not ok');
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
alter table "public"."teams-members" add constraint "public_teams-members_team_id_fkey" FOREIGN KEY (team_id) REFERENCES teams(team_id) ON UPDATE CASCADE ON DELETE CASCADE not valid;

alter table "public"."teams-members" validate constraint "public_teams-members_team_id_fkey";

set check_function_bodies = off;

CREATE OR REPLACE FUNCTION public.update_teams_joined(requester_id uuid, user_id uuid, updated_teams_joined smallint)
RETURNS void
LANGUAGE plpgsql
SECURITY DEFINER
AS $function$
BEGIN
UPDATE profiles
SET teams_joined = updated_teams_joined
WHERE id = user_id;
END;
$function$
;


0 comments on commit 9021263

Please sign in to comment.