feat: implement full-stack ratings system for appointments with user submission and pending ratings dashboard integration
This commit is contained in:
@@ -3,6 +3,26 @@ import { ApiError } from "@models/Server.Error.model";
|
||||
import axios from "@config/axios.config";
|
||||
|
||||
class ApiService {
|
||||
private normalizeError(error: unknown): ApiError {
|
||||
if (error && typeof error === "object" && "response" in error) {
|
||||
const response = (error as { response?: { data?: any; status?: number } }).response;
|
||||
const data = response?.data;
|
||||
|
||||
if (data) {
|
||||
const msg = data.desc || data.message || JSON.stringify(data.details || data) || "No pudimos completar la operación.";
|
||||
return new ApiError(data.code || response?.status || 500, msg);
|
||||
}
|
||||
|
||||
return new ApiError(response?.status || 500, "No pudimos comunicarnos con el servidor.");
|
||||
}
|
||||
|
||||
if (error instanceof Error) {
|
||||
return new ApiError(500, error.message);
|
||||
}
|
||||
|
||||
return new ApiError(500, "No pudimos comunicarnos con el servidor.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a HTTP POST request to the specified endpoint with the provided data
|
||||
* and returns a promise that resolves to the response data.
|
||||
@@ -19,14 +39,7 @@ class ApiService {
|
||||
resolve(response.data);
|
||||
})
|
||||
.catch((error) => {
|
||||
try {
|
||||
const data = error.response.data;
|
||||
const msg = data.desc || data.message || JSON.stringify(data.details || data);
|
||||
reject(new ApiError(data.code || error.response.status || 500, msg));
|
||||
} catch {
|
||||
const errorMessage = process.env.VITE_API_UNAVAILABLE as string;
|
||||
reject(new ApiError(500, errorMessage));
|
||||
}
|
||||
reject(this.normalizeError(error));
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -44,16 +57,7 @@ class ApiService {
|
||||
resolve(response.data);
|
||||
})
|
||||
.catch((error) => {
|
||||
try {
|
||||
console.error("Full API Error:", error.response?.data);
|
||||
const data = error.response.data;
|
||||
const msg = data.desc || data.message || JSON.stringify(data.details || data);
|
||||
reject(new ApiError(data.code || error.response.status || 500, msg));
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
const errorMessage = process.env.VITE_API_UNAVAILABLE as string;
|
||||
reject(new ApiError(500, errorMessage));
|
||||
}
|
||||
reject(this.normalizeError(error));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
import ApiRequest from "@services/Api.Service";
|
||||
import { ApiVoidResult } from "@core/Models/Api.VoidResult.type";
|
||||
import { ApiError } from "@core/Models/Server.Error.model";
|
||||
import {
|
||||
CreateRatingParams,
|
||||
PendingRatingItem,
|
||||
PendingRatingsByUserParams,
|
||||
RATING_COMMENT_MAX_LENGTH,
|
||||
RatingTargetType,
|
||||
} from "@core/Models/Ratings.model";
|
||||
import * as Yup from "yup";
|
||||
|
||||
const schemaPendingRatingsByUser = Yup.object().shape({
|
||||
sessionUser: Yup.string().required("Para ver tus calificaciones pendientes debes iniciar sesión."),
|
||||
});
|
||||
|
||||
const schemaCreateRating = Yup.object().shape({
|
||||
appointmentId: Yup.string().required("No se ha proporcionado el turno."),
|
||||
targetType: Yup.string()
|
||||
.oneOf(Object.values(RatingTargetType), "El tipo de calificación no es válido.")
|
||||
.required("No se ha proporcionado el tipo de calificación."),
|
||||
targetId: Yup.string().required("No se ha proporcionado el item a calificar."),
|
||||
score: Yup.number().integer().min(1).max(5).required("Selecciona una calificación."),
|
||||
comment: Yup.string().max(RATING_COMMENT_MAX_LENGTH, `El comentario no puede superar los ${RATING_COMMENT_MAX_LENGTH} caracteres.`),
|
||||
sessionUser: Yup.string().required("Para calificar debes iniciar sesión."),
|
||||
});
|
||||
|
||||
export const pendingRatingsByUser = async (data: PendingRatingsByUserParams): Promise<PendingRatingItem[]> => {
|
||||
return new Promise<PendingRatingItem[]>((resolve, reject) => {
|
||||
schemaPendingRatingsByUser
|
||||
.validate(data, { abortEarly: true })
|
||||
.then(() => {
|
||||
resolve(ApiRequest.post<PendingRatingItem[]>("ratings/pending-by-user", data));
|
||||
})
|
||||
.catch((error) => {
|
||||
reject(new ApiError(500, error.message));
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
export const createRating = async (data: CreateRatingParams): Promise<ApiVoidResult> => {
|
||||
return new Promise<ApiVoidResult>((resolve, reject) => {
|
||||
schemaCreateRating
|
||||
.validate(data, { abortEarly: true })
|
||||
.then(() => {
|
||||
resolve(ApiRequest.post<ApiVoidResult>("ratings/create", data));
|
||||
})
|
||||
.catch((error) => {
|
||||
reject(new ApiError(500, error.message));
|
||||
});
|
||||
});
|
||||
};
|
||||
Reference in New Issue
Block a user