Add house leaderboard feature: Integrate house leaderboard functionality in LeaderboardPage and LeaderboardSection components. Update userStatsService to fetch house leaderboard data, and enhance UI to display house rankings, scores, and member details. Update Prisma schema to include house-related models and relationships, and seed database with initial house data.
Some checks failed
Deploy with Docker Compose / deploy (push) Has been cancelled
Some checks failed
Deploy with Docker Compose / deploy (push) Has been cancelled
This commit is contained in:
48
actions/houses/create.ts
Normal file
48
actions/houses/create.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
"use server";
|
||||
|
||||
import { revalidatePath } from "next/cache";
|
||||
import { auth } from "@/lib/auth";
|
||||
import { houseService } from "@/services/houses/house.service";
|
||||
import {
|
||||
ValidationError,
|
||||
ConflictError,
|
||||
} from "@/services/errors";
|
||||
|
||||
export async function createHouse(data: {
|
||||
name: string;
|
||||
description?: string | null;
|
||||
}) {
|
||||
try {
|
||||
const session = await auth();
|
||||
|
||||
if (!session?.user?.id) {
|
||||
return {
|
||||
success: false,
|
||||
error: "Vous devez être connecté pour créer une maison",
|
||||
};
|
||||
}
|
||||
|
||||
const house = await houseService.createHouse({
|
||||
name: data.name,
|
||||
description: data.description,
|
||||
creatorId: session.user.id,
|
||||
});
|
||||
|
||||
revalidatePath("/houses");
|
||||
revalidatePath("/profile");
|
||||
|
||||
return { success: true, message: "Maison créée avec succès", data: house };
|
||||
} catch (error) {
|
||||
console.error("Create house error:", error);
|
||||
|
||||
if (error instanceof ValidationError || error instanceof ConflictError) {
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
|
||||
return {
|
||||
success: false,
|
||||
error: "Une erreur est survenue lors de la création de la maison",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
173
actions/houses/invitations.ts
Normal file
173
actions/houses/invitations.ts
Normal file
@@ -0,0 +1,173 @@
|
||||
"use server";
|
||||
|
||||
import { revalidatePath } from "next/cache";
|
||||
import { auth } from "@/lib/auth";
|
||||
import { houseService } from "@/services/houses/house.service";
|
||||
import {
|
||||
ValidationError,
|
||||
ConflictError,
|
||||
ForbiddenError,
|
||||
NotFoundError,
|
||||
} from "@/services/errors";
|
||||
|
||||
export async function inviteUser(houseId: string, inviteeId: string) {
|
||||
try {
|
||||
const session = await auth();
|
||||
|
||||
if (!session?.user?.id) {
|
||||
return {
|
||||
success: false,
|
||||
error: "Vous devez être connecté",
|
||||
};
|
||||
}
|
||||
|
||||
const invitation = await houseService.inviteUser({
|
||||
houseId,
|
||||
inviterId: session.user.id,
|
||||
inviteeId,
|
||||
});
|
||||
|
||||
revalidatePath("/houses");
|
||||
revalidatePath(`/houses/${houseId}`);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "Invitation envoyée",
|
||||
data: invitation,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("Invite user error:", error);
|
||||
|
||||
if (
|
||||
error instanceof ValidationError ||
|
||||
error instanceof ConflictError ||
|
||||
error instanceof ForbiddenError
|
||||
) {
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
|
||||
return {
|
||||
success: false,
|
||||
error: "Une erreur est survenue lors de l'envoi de l'invitation",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export async function acceptInvitation(invitationId: string) {
|
||||
try {
|
||||
const session = await auth();
|
||||
|
||||
if (!session?.user?.id) {
|
||||
return {
|
||||
success: false,
|
||||
error: "Vous devez être connecté",
|
||||
};
|
||||
}
|
||||
|
||||
const membership = await houseService.acceptInvitation(
|
||||
invitationId,
|
||||
session.user.id
|
||||
);
|
||||
|
||||
revalidatePath("/houses");
|
||||
revalidatePath("/profile");
|
||||
revalidatePath("/invitations");
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "Invitation acceptée",
|
||||
data: membership,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("Accept invitation error:", error);
|
||||
|
||||
if (
|
||||
error instanceof ValidationError ||
|
||||
error instanceof ConflictError ||
|
||||
error instanceof ForbiddenError ||
|
||||
error instanceof NotFoundError
|
||||
) {
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
|
||||
return {
|
||||
success: false,
|
||||
error: "Une erreur est survenue lors de l'acceptation de l'invitation",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export async function rejectInvitation(invitationId: string) {
|
||||
try {
|
||||
const session = await auth();
|
||||
|
||||
if (!session?.user?.id) {
|
||||
return {
|
||||
success: false,
|
||||
error: "Vous devez être connecté",
|
||||
};
|
||||
}
|
||||
|
||||
await houseService.rejectInvitation(invitationId, session.user.id);
|
||||
|
||||
revalidatePath("/houses");
|
||||
revalidatePath("/invitations");
|
||||
|
||||
return { success: true, message: "Invitation refusée" };
|
||||
} catch (error) {
|
||||
console.error("Reject invitation error:", error);
|
||||
|
||||
if (
|
||||
error instanceof ConflictError ||
|
||||
error instanceof ForbiddenError ||
|
||||
error instanceof NotFoundError
|
||||
) {
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
|
||||
return {
|
||||
success: false,
|
||||
error: "Une erreur est survenue lors du refus de l'invitation",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export async function cancelInvitation(invitationId: string) {
|
||||
try {
|
||||
const session = await auth();
|
||||
|
||||
if (!session?.user?.id) {
|
||||
return {
|
||||
success: false,
|
||||
error: "Vous devez être connecté",
|
||||
};
|
||||
}
|
||||
|
||||
// Récupérer l'invitation pour obtenir le houseId avant de l'annuler
|
||||
const invitation = await houseService.getInvitationById(invitationId);
|
||||
|
||||
await houseService.cancelInvitation(invitationId, session.user.id);
|
||||
|
||||
revalidatePath("/houses");
|
||||
if (invitation?.houseId) {
|
||||
revalidatePath(`/houses/${invitation.houseId}`);
|
||||
}
|
||||
|
||||
return { success: true, message: "Invitation annulée" };
|
||||
} catch (error) {
|
||||
console.error("Cancel invitation error:", error);
|
||||
|
||||
if (
|
||||
error instanceof ConflictError ||
|
||||
error instanceof ForbiddenError ||
|
||||
error instanceof NotFoundError
|
||||
) {
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
|
||||
return {
|
||||
success: false,
|
||||
error: "Une erreur est survenue lors de l'annulation de l'invitation",
|
||||
};
|
||||
}
|
||||
}
|
||||
163
actions/houses/requests.ts
Normal file
163
actions/houses/requests.ts
Normal file
@@ -0,0 +1,163 @@
|
||||
"use server";
|
||||
|
||||
import { revalidatePath } from "next/cache";
|
||||
import { auth } from "@/lib/auth";
|
||||
import { houseService } from "@/services/houses/house.service";
|
||||
import {
|
||||
ValidationError,
|
||||
ConflictError,
|
||||
ForbiddenError,
|
||||
NotFoundError,
|
||||
} from "@/services/errors";
|
||||
|
||||
export async function requestToJoin(houseId: string) {
|
||||
try {
|
||||
const session = await auth();
|
||||
|
||||
if (!session?.user?.id) {
|
||||
return {
|
||||
success: false,
|
||||
error: "Vous devez être connecté",
|
||||
};
|
||||
}
|
||||
|
||||
const request = await houseService.requestToJoin({
|
||||
houseId,
|
||||
requesterId: session.user.id,
|
||||
});
|
||||
|
||||
revalidatePath("/houses");
|
||||
revalidatePath(`/houses/${houseId}`);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "Demande envoyée",
|
||||
data: request,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("Request to join error:", error);
|
||||
|
||||
if (
|
||||
error instanceof ValidationError ||
|
||||
error instanceof ConflictError
|
||||
) {
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
|
||||
return {
|
||||
success: false,
|
||||
error: "Une erreur est survenue lors de l'envoi de la demande",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export async function acceptRequest(requestId: string) {
|
||||
try {
|
||||
const session = await auth();
|
||||
|
||||
if (!session?.user?.id) {
|
||||
return {
|
||||
success: false,
|
||||
error: "Vous devez être connecté",
|
||||
};
|
||||
}
|
||||
|
||||
const membership = await houseService.acceptRequest(
|
||||
requestId,
|
||||
session.user.id
|
||||
);
|
||||
|
||||
revalidatePath("/houses");
|
||||
revalidatePath("/profile");
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: "Demande acceptée",
|
||||
data: membership,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("Accept request error:", error);
|
||||
|
||||
if (
|
||||
error instanceof ConflictError ||
|
||||
error instanceof ForbiddenError ||
|
||||
error instanceof NotFoundError
|
||||
) {
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
|
||||
return {
|
||||
success: false,
|
||||
error: "Une erreur est survenue lors de l'acceptation de la demande",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export async function rejectRequest(requestId: string) {
|
||||
try {
|
||||
const session = await auth();
|
||||
|
||||
if (!session?.user?.id) {
|
||||
return {
|
||||
success: false,
|
||||
error: "Vous devez être connecté",
|
||||
};
|
||||
}
|
||||
|
||||
await houseService.rejectRequest(requestId, session.user.id);
|
||||
|
||||
revalidatePath("/houses");
|
||||
|
||||
return { success: true, message: "Demande refusée" };
|
||||
} catch (error) {
|
||||
console.error("Reject request error:", error);
|
||||
|
||||
if (
|
||||
error instanceof ConflictError ||
|
||||
error instanceof ForbiddenError ||
|
||||
error instanceof NotFoundError
|
||||
) {
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
|
||||
return {
|
||||
success: false,
|
||||
error: "Une erreur est survenue lors du refus de la demande",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export async function cancelRequest(requestId: string) {
|
||||
try {
|
||||
const session = await auth();
|
||||
|
||||
if (!session?.user?.id) {
|
||||
return {
|
||||
success: false,
|
||||
error: "Vous devez être connecté",
|
||||
};
|
||||
}
|
||||
|
||||
await houseService.cancelRequest(requestId, session.user.id);
|
||||
|
||||
revalidatePath("/houses");
|
||||
|
||||
return { success: true, message: "Demande annulée" };
|
||||
} catch (error) {
|
||||
console.error("Cancel request error:", error);
|
||||
|
||||
if (
|
||||
error instanceof ConflictError ||
|
||||
error instanceof ForbiddenError ||
|
||||
error instanceof NotFoundError
|
||||
) {
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
|
||||
return {
|
||||
success: false,
|
||||
error: "Une erreur est survenue lors de l'annulation de la demande",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
114
actions/houses/update.ts
Normal file
114
actions/houses/update.ts
Normal file
@@ -0,0 +1,114 @@
|
||||
"use server";
|
||||
|
||||
import { revalidatePath } from "next/cache";
|
||||
import { auth } from "@/lib/auth";
|
||||
import { houseService } from "@/services/houses/house.service";
|
||||
import {
|
||||
ValidationError,
|
||||
ConflictError,
|
||||
ForbiddenError,
|
||||
} from "@/services/errors";
|
||||
|
||||
export async function updateHouse(
|
||||
houseId: string,
|
||||
data: {
|
||||
name?: string;
|
||||
description?: string | null;
|
||||
}
|
||||
) {
|
||||
try {
|
||||
const session = await auth();
|
||||
|
||||
if (!session?.user?.id) {
|
||||
return {
|
||||
success: false,
|
||||
error: "Vous devez être connecté",
|
||||
};
|
||||
}
|
||||
|
||||
const house = await houseService.updateHouse(houseId, session.user.id, data);
|
||||
|
||||
revalidatePath("/houses");
|
||||
revalidatePath(`/houses/${houseId}`);
|
||||
|
||||
return { success: true, message: "Maison mise à jour", data: house };
|
||||
} catch (error) {
|
||||
console.error("Update house error:", error);
|
||||
|
||||
if (
|
||||
error instanceof ValidationError ||
|
||||
error instanceof ConflictError ||
|
||||
error instanceof ForbiddenError
|
||||
) {
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
|
||||
return {
|
||||
success: false,
|
||||
error: "Une erreur est survenue lors de la mise à jour de la maison",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export async function deleteHouse(houseId: string) {
|
||||
try {
|
||||
const session = await auth();
|
||||
|
||||
if (!session?.user?.id) {
|
||||
return {
|
||||
success: false,
|
||||
error: "Vous devez être connecté",
|
||||
};
|
||||
}
|
||||
|
||||
await houseService.deleteHouse(houseId, session.user.id);
|
||||
|
||||
revalidatePath("/houses");
|
||||
revalidatePath("/profile");
|
||||
|
||||
return { success: true, message: "Maison supprimée" };
|
||||
} catch (error) {
|
||||
console.error("Delete house error:", error);
|
||||
|
||||
if (error instanceof ForbiddenError) {
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
|
||||
return {
|
||||
success: false,
|
||||
error: "Une erreur est survenue lors de la suppression de la maison",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export async function leaveHouse(houseId: string) {
|
||||
try {
|
||||
const session = await auth();
|
||||
|
||||
if (!session?.user?.id) {
|
||||
return {
|
||||
success: false,
|
||||
error: "Vous devez être connecté",
|
||||
};
|
||||
}
|
||||
|
||||
await houseService.leaveHouse(houseId, session.user.id);
|
||||
|
||||
revalidatePath("/houses");
|
||||
revalidatePath("/profile");
|
||||
|
||||
return { success: true, message: "Vous avez quitté la maison" };
|
||||
} catch (error) {
|
||||
console.error("Leave house error:", error);
|
||||
|
||||
if (error instanceof ForbiddenError) {
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
|
||||
return {
|
||||
success: false,
|
||||
error: "Une erreur est survenue lors de la sortie de la maison",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user