Feat: front-end service et store pour les sous traitant
This commit is contained in:
parent
7506bdcf8b
commit
8c6787d03e
@ -1,3 +1,4 @@
|
||||
export * from "./http";
|
||||
export { default as AuthService } from "./auth";
|
||||
export { default as WebmailService } from "./webmail";
|
||||
export { default as SousTraitantService } from "./sousTraitant";
|
||||
|
||||
189
thanasoft-front/src/services/sousTraitant.ts
Normal file
189
thanasoft-front/src/services/sousTraitant.ts
Normal file
@ -0,0 +1,189 @@
|
||||
import { request } from "./http";
|
||||
|
||||
export type SousTraitantStatut = "actif" | "inactif" | "en_evaluation";
|
||||
|
||||
export interface SousTraitant {
|
||||
id: number;
|
||||
nom_entreprise: string;
|
||||
siret: string | null;
|
||||
forme_juridique: string | null;
|
||||
code_ape: string | null;
|
||||
adresse: string | null;
|
||||
contact_principal: string;
|
||||
telephone: string | null;
|
||||
email: string | null;
|
||||
site_web: string | null;
|
||||
numero_contrat: string | null;
|
||||
montant_contrat: string | number | null;
|
||||
date_debut_contrat: string | null;
|
||||
date_fin_contrat: string | null;
|
||||
type_prestation: string | null;
|
||||
conditions_paiement: string | null;
|
||||
statut: SousTraitantStatut;
|
||||
note_qualite: string | number | null;
|
||||
certifications_labels: string[];
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
export interface SousTraitantListResponse {
|
||||
data: SousTraitant[];
|
||||
meta?: {
|
||||
current_page: number;
|
||||
last_page: number;
|
||||
per_page: number;
|
||||
total: number;
|
||||
from?: number;
|
||||
to?: number;
|
||||
stats?: {
|
||||
actif: number;
|
||||
inactif: number;
|
||||
en_evaluation: number;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export interface SousTraitantResponse {
|
||||
data: SousTraitant;
|
||||
}
|
||||
|
||||
export interface CreateSousTraitantPayload {
|
||||
nom_entreprise: string;
|
||||
siret?: string | null;
|
||||
forme_juridique?: string | null;
|
||||
code_ape?: string | null;
|
||||
adresse?: string | null;
|
||||
contact_principal: string;
|
||||
telephone?: string | null;
|
||||
email?: string | null;
|
||||
site_web?: string | null;
|
||||
numero_contrat?: string | null;
|
||||
montant_contrat?: number | string | null;
|
||||
date_debut_contrat?: string | null;
|
||||
date_fin_contrat?: string | null;
|
||||
type_prestation?: string | null;
|
||||
conditions_paiement?: string | null;
|
||||
statut?: SousTraitantStatut;
|
||||
note_qualite?: number | string | null;
|
||||
certifications_labels?: string[];
|
||||
}
|
||||
|
||||
export interface UpdateSousTraitantPayload
|
||||
extends Partial<CreateSousTraitantPayload> {
|
||||
id: number;
|
||||
}
|
||||
|
||||
export const SousTraitantService = {
|
||||
async getAllSousTraitants(params?: {
|
||||
page?: number;
|
||||
per_page?: number;
|
||||
search?: string;
|
||||
statut?: SousTraitantStatut;
|
||||
sort_by?: string;
|
||||
sort_direction?: "asc" | "desc";
|
||||
}): Promise<SousTraitantListResponse> {
|
||||
const response = await request<SousTraitantListResponse>({
|
||||
url: "/api/sous-traitants",
|
||||
method: "get",
|
||||
params,
|
||||
});
|
||||
|
||||
return response;
|
||||
},
|
||||
|
||||
async getSousTraitant(id: number): Promise<SousTraitantResponse> {
|
||||
const response = await request<SousTraitantResponse>({
|
||||
url: `/api/sous-traitants/${id}`,
|
||||
method: "get",
|
||||
});
|
||||
|
||||
return response;
|
||||
},
|
||||
|
||||
async createSousTraitant(
|
||||
payload: CreateSousTraitantPayload
|
||||
): Promise<SousTraitantResponse> {
|
||||
const formattedPayload = this.transformSousTraitantPayload(payload);
|
||||
|
||||
const response = await request<SousTraitantResponse>({
|
||||
url: "/api/sous-traitants",
|
||||
method: "post",
|
||||
data: formattedPayload,
|
||||
});
|
||||
|
||||
return response;
|
||||
},
|
||||
|
||||
async updateSousTraitant(
|
||||
payload: UpdateSousTraitantPayload
|
||||
): Promise<SousTraitantResponse> {
|
||||
const { id, ...updateData } = payload;
|
||||
const formattedPayload = this.transformSousTraitantPayload(updateData);
|
||||
|
||||
const response = await request<SousTraitantResponse>({
|
||||
url: `/api/sous-traitants/${id}`,
|
||||
method: "put",
|
||||
data: formattedPayload,
|
||||
});
|
||||
|
||||
return response;
|
||||
},
|
||||
|
||||
async deleteSousTraitant(
|
||||
id: number
|
||||
): Promise<{ success?: boolean; message: string }> {
|
||||
const response = await request<{ success?: boolean; message: string }>({
|
||||
url: `/api/sous-traitants/${id}`,
|
||||
method: "delete",
|
||||
});
|
||||
|
||||
return response;
|
||||
},
|
||||
|
||||
transformSousTraitantPayload(
|
||||
payload: Partial<CreateSousTraitantPayload>
|
||||
): Record<string, unknown> {
|
||||
const transformed: Record<string, unknown> = { ...payload };
|
||||
|
||||
if (
|
||||
Array.isArray(transformed.certifications_labels) &&
|
||||
transformed.certifications_labels.length > 0
|
||||
) {
|
||||
transformed.certifications_labels = transformed.certifications_labels
|
||||
.map((item) => (typeof item === "string" ? item.trim() : item))
|
||||
.filter(Boolean);
|
||||
}
|
||||
|
||||
Object.keys(transformed).forEach((key) => {
|
||||
if (transformed[key] === undefined) {
|
||||
delete transformed[key];
|
||||
}
|
||||
});
|
||||
|
||||
return transformed;
|
||||
},
|
||||
|
||||
async searchSousTraitants(
|
||||
query: string,
|
||||
params?: {
|
||||
exact_match?: boolean;
|
||||
}
|
||||
): Promise<SousTraitant[]> {
|
||||
const response = await request<{
|
||||
data: SousTraitant[];
|
||||
count: number;
|
||||
message: string;
|
||||
}>({
|
||||
url: "/api/sous-traitants/searchBy",
|
||||
method: "get",
|
||||
params: {
|
||||
name: query,
|
||||
exact_match: params?.exact_match || false,
|
||||
},
|
||||
});
|
||||
|
||||
return response.data;
|
||||
},
|
||||
};
|
||||
|
||||
export default SousTraitantService;
|
||||
345
thanasoft-front/src/stores/sousTraitantStore.ts
Normal file
345
thanasoft-front/src/stores/sousTraitantStore.ts
Normal file
@ -0,0 +1,345 @@
|
||||
import { defineStore } from "pinia";
|
||||
import { computed, ref } from "vue";
|
||||
import SousTraitantService from "@/services/sousTraitant";
|
||||
|
||||
import type {
|
||||
CreateSousTraitantPayload,
|
||||
SousTraitant,
|
||||
SousTraitantStatut,
|
||||
UpdateSousTraitantPayload,
|
||||
} from "@/services/sousTraitant";
|
||||
|
||||
export const useSousTraitantStore = defineStore("sousTraitant", () => {
|
||||
const sousTraitants = ref<SousTraitant[]>([]);
|
||||
const currentSousTraitant = ref<SousTraitant | null>(null);
|
||||
const loading = ref(false);
|
||||
const error = ref<string | null>(null);
|
||||
const searchResults = ref<SousTraitant[]>([]);
|
||||
const filters = ref<{
|
||||
page: number;
|
||||
per_page: number;
|
||||
search?: string;
|
||||
statut?: SousTraitantStatut;
|
||||
sort_by?: string;
|
||||
sort_direction?: "asc" | "desc";
|
||||
}>({
|
||||
page: 1,
|
||||
per_page: 10,
|
||||
sort_by: "created_at",
|
||||
sort_direction: "desc",
|
||||
});
|
||||
|
||||
const pagination = ref({
|
||||
current_page: 1,
|
||||
last_page: 1,
|
||||
per_page: 10,
|
||||
total: 0,
|
||||
from: 0,
|
||||
to: 0,
|
||||
});
|
||||
|
||||
const allSousTraitants = computed(() => sousTraitants.value);
|
||||
const activeSousTraitants = computed(() =>
|
||||
sousTraitants.value.filter((item) => item.statut === "actif")
|
||||
);
|
||||
const inactiveSousTraitants = computed(() =>
|
||||
sousTraitants.value.filter((item) => item.statut === "inactif")
|
||||
);
|
||||
const evaluatingSousTraitants = computed(() =>
|
||||
sousTraitants.value.filter((item) => item.statut === "en_evaluation")
|
||||
);
|
||||
const isLoading = computed(() => loading.value);
|
||||
const hasError = computed(() => error.value !== null);
|
||||
const getError = computed(() => error.value);
|
||||
const getPagination = computed(() => pagination.value);
|
||||
const getSousTraitantById = computed(() => (id: number) =>
|
||||
sousTraitants.value.find((item) => item.id === id)
|
||||
);
|
||||
|
||||
const setLoading = (isLoading: boolean) => {
|
||||
loading.value = isLoading;
|
||||
};
|
||||
|
||||
const setError = (err: string | null) => {
|
||||
error.value = err;
|
||||
};
|
||||
|
||||
const clearError = () => {
|
||||
error.value = null;
|
||||
};
|
||||
|
||||
const setSousTraitants = (items: SousTraitant[]) => {
|
||||
sousTraitants.value = items;
|
||||
};
|
||||
|
||||
const setCurrentSousTraitant = (item: SousTraitant | null) => {
|
||||
currentSousTraitant.value = item;
|
||||
};
|
||||
|
||||
const setSearchResults = (items: SousTraitant[]) => {
|
||||
searchResults.value = items;
|
||||
};
|
||||
|
||||
const setPagination = (meta: any) => {
|
||||
if (meta) {
|
||||
const getValue = (val: any) => (Array.isArray(val) ? val[0] : val);
|
||||
pagination.value = {
|
||||
current_page: Number(getValue(meta.current_page)) || 1,
|
||||
last_page: Number(getValue(meta.last_page)) || 1,
|
||||
per_page: Number(getValue(meta.per_page)) || 10,
|
||||
total: Number(getValue(meta.total)) || 0,
|
||||
from: Number(getValue(meta.from)) || 0,
|
||||
to: Number(getValue(meta.to)) || 0,
|
||||
};
|
||||
|
||||
filters.value = {
|
||||
...filters.value,
|
||||
page: pagination.value.current_page,
|
||||
per_page: pagination.value.per_page,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const setFilters = (params?: {
|
||||
page?: number;
|
||||
per_page?: number;
|
||||
search?: string;
|
||||
statut?: SousTraitantStatut;
|
||||
sort_by?: string;
|
||||
sort_direction?: "asc" | "desc";
|
||||
}) => {
|
||||
filters.value = {
|
||||
...filters.value,
|
||||
...params,
|
||||
page: params?.page ?? filters.value.page ?? 1,
|
||||
per_page: params?.per_page ?? filters.value.per_page ?? 10,
|
||||
};
|
||||
};
|
||||
|
||||
const fetchSousTraitants = async (params?: {
|
||||
page?: number;
|
||||
per_page?: number;
|
||||
search?: string;
|
||||
statut?: SousTraitantStatut;
|
||||
sort_by?: string;
|
||||
sort_direction?: "asc" | "desc";
|
||||
}) => {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
|
||||
try {
|
||||
setFilters(params);
|
||||
|
||||
const requestParams = Object.fromEntries(
|
||||
Object.entries(filters.value).filter(
|
||||
([, value]) => value !== undefined && value !== null && value !== ""
|
||||
)
|
||||
) as {
|
||||
page?: number;
|
||||
per_page?: number;
|
||||
search?: string;
|
||||
statut?: SousTraitantStatut;
|
||||
sort_by?: string;
|
||||
sort_direction?: "asc" | "desc";
|
||||
};
|
||||
|
||||
const response =
|
||||
await SousTraitantService.getAllSousTraitants(requestParams);
|
||||
setSousTraitants(response.data);
|
||||
if (response.meta) {
|
||||
setPagination(response.meta);
|
||||
}
|
||||
return response;
|
||||
} catch (err: any) {
|
||||
const errorMessage =
|
||||
err.response?.data?.message ||
|
||||
err.message ||
|
||||
"Failed to fetch sous-traitants";
|
||||
setError(errorMessage);
|
||||
throw err;
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const fetchSousTraitant = async (id: number) => {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
|
||||
try {
|
||||
const response = await SousTraitantService.getSousTraitant(id);
|
||||
setCurrentSousTraitant(response.data);
|
||||
return response.data;
|
||||
} catch (err: any) {
|
||||
const errorMessage =
|
||||
err.response?.data?.message ||
|
||||
err.message ||
|
||||
"Failed to fetch sous-traitant";
|
||||
setError(errorMessage);
|
||||
throw err;
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const createSousTraitant = async (payload: CreateSousTraitantPayload) => {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
|
||||
try {
|
||||
const response = await SousTraitantService.createSousTraitant(payload);
|
||||
sousTraitants.value.push(response.data);
|
||||
setCurrentSousTraitant(response.data);
|
||||
return response.data;
|
||||
} catch (err: any) {
|
||||
const errorMessage =
|
||||
err.response?.data?.message ||
|
||||
err.message ||
|
||||
"Failed to create sous-traitant";
|
||||
setError(errorMessage);
|
||||
throw err;
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const updateSousTraitant = async (payload: UpdateSousTraitantPayload) => {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
|
||||
try {
|
||||
const response = await SousTraitantService.updateSousTraitant(payload);
|
||||
const updatedSousTraitant = response.data;
|
||||
|
||||
const index = sousTraitants.value.findIndex(
|
||||
(item) => item.id === updatedSousTraitant.id
|
||||
);
|
||||
if (index !== -1) {
|
||||
sousTraitants.value[index] = updatedSousTraitant;
|
||||
}
|
||||
|
||||
if (
|
||||
currentSousTraitant.value &&
|
||||
currentSousTraitant.value.id === updatedSousTraitant.id
|
||||
) {
|
||||
setCurrentSousTraitant(updatedSousTraitant);
|
||||
}
|
||||
|
||||
return updatedSousTraitant;
|
||||
} catch (err: any) {
|
||||
const errorMessage =
|
||||
err.response?.data?.message ||
|
||||
err.message ||
|
||||
"Failed to update sous-traitant";
|
||||
setError(errorMessage);
|
||||
throw err;
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const deleteSousTraitant = async (id: number) => {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
|
||||
try {
|
||||
const response = await SousTraitantService.deleteSousTraitant(id);
|
||||
|
||||
sousTraitants.value = sousTraitants.value.filter((item) => item.id !== id);
|
||||
|
||||
if (currentSousTraitant.value && currentSousTraitant.value.id === id) {
|
||||
setCurrentSousTraitant(null);
|
||||
}
|
||||
|
||||
return response;
|
||||
} catch (err: any) {
|
||||
const errorMessage =
|
||||
err.response?.data?.message ||
|
||||
err.message ||
|
||||
"Failed to delete sous-traitant";
|
||||
setError(errorMessage);
|
||||
throw err;
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const searchSousTraitants = async (
|
||||
query: string,
|
||||
exactMatch: boolean = false
|
||||
) => {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
|
||||
try {
|
||||
const results = await SousTraitantService.searchSousTraitants(query, {
|
||||
exact_match: exactMatch,
|
||||
});
|
||||
setSearchResults(results);
|
||||
return results;
|
||||
} catch (err) {
|
||||
setError("Erreur lors de la recherche des sous-traitants");
|
||||
console.error("Error searching sous-traitants:", err);
|
||||
setSearchResults([]);
|
||||
throw err;
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const clearCurrentSousTraitant = () => {
|
||||
setCurrentSousTraitant(null);
|
||||
};
|
||||
|
||||
const clearStore = () => {
|
||||
sousTraitants.value = [];
|
||||
currentSousTraitant.value = null;
|
||||
searchResults.value = [];
|
||||
error.value = null;
|
||||
pagination.value = {
|
||||
current_page: 1,
|
||||
last_page: 1,
|
||||
per_page: 10,
|
||||
total: 0,
|
||||
from: 0,
|
||||
to: 0,
|
||||
};
|
||||
filters.value = {
|
||||
page: 1,
|
||||
per_page: 10,
|
||||
sort_by: "created_at",
|
||||
sort_direction: "desc",
|
||||
};
|
||||
};
|
||||
|
||||
return {
|
||||
sousTraitants,
|
||||
currentSousTraitant,
|
||||
loading,
|
||||
error,
|
||||
searchResults,
|
||||
filters,
|
||||
|
||||
allSousTraitants,
|
||||
activeSousTraitants,
|
||||
inactiveSousTraitants,
|
||||
evaluatingSousTraitants,
|
||||
isLoading,
|
||||
hasError,
|
||||
getError,
|
||||
getPagination,
|
||||
getSousTraitantById,
|
||||
|
||||
fetchSousTraitants,
|
||||
fetchSousTraitant,
|
||||
createSousTraitant,
|
||||
updateSousTraitant,
|
||||
deleteSousTraitant,
|
||||
searchSousTraitants,
|
||||
clearCurrentSousTraitant,
|
||||
clearStore,
|
||||
clearError,
|
||||
};
|
||||
});
|
||||
|
||||
export default useSousTraitantStore;
|
||||
Loading…
x
Reference in New Issue
Block a user