diff --git a/app/composables/useAdmin.ts b/app/composables/useAdmin.ts new file mode 100644 index 0000000..2730497 --- /dev/null +++ b/app/composables/useAdmin.ts @@ -0,0 +1,61 @@ +import type { + AreaListResponse, CategoryListResponse, CreateAreaRequest, CreateCategoryRequest, CreateTeamRequest, + ModerationListResponse, + OkResponse, + OverviewStatsResponse, TeamListResponse, UpdateModerationRequest, + UpdateUserBanRequest, UpdateUserRolesRequest, + UserListResponse +} from "~/types/api"; + +export const useAdmin = () => { + const getOverviewStats = () => + useApiFetch('/api/v1/admin/stats/overview', { method: 'GET' }) + + const getUsers = () => + useApiFetch('/api/v1/admin/users', { method: 'GET' }) + + const updateUserBan = (id: number, body: UpdateUserBanRequest) => + useApiFetch(`/api/v1/admin/users/${id}/ban`, { method: 'PATCH', body }) + + const updateUserRoles = (id: number, body: UpdateUserRolesRequest) => + useApiFetch(`/api/v1/admin/users/${id}/roles`, { method: 'PATCH', body }) + + const getAreas = () => + useApiFetch('/api/v1/admin/areas', { method: 'GET' }) + + const createArea = (body: CreateAreaRequest) => + useApiFetch('/api/v1/admin/areas', { method: 'POST', body }) + + const getCategories = () => + useApiFetch('/api/v1/admin/categories', { method: 'GET' }) + + const createCategory = (body: CreateCategoryRequest) => + useApiFetch('/api/v1/admin/categories', { method: 'POST', body }) + + const getTeams = () => + useApiFetch('/api/v1/admin/teams', { method: 'GET' }) + + const createTeam = (body: CreateTeamRequest) => + useApiFetch('/api/v1/admin/teams', { method: 'POST', body }) + + const getModerationFlags = (query?: { status?: string; page?: number; per_page?: number }) => + useApiFetch('/api/v1/admin/moderation', { method: 'GET', query }) + + const updateModerationFlag = (id: number, body: UpdateModerationRequest) => + useApiFetch(`/api/v1/admin/moderation/${id}`, { method: 'PATCH', body }) + + return { + getOverviewStats, + getUsers, + updateUserBan, + updateUserRoles, + getAreas, + createArea, + getCategories, + createCategory, + getTeams, + createTeam, + getModerationFlags, + updateModerationFlag, + } +} \ No newline at end of file diff --git a/app/composables/useApiFetch.ts b/app/composables/useApiFetch.ts new file mode 100644 index 0000000..2a8899f --- /dev/null +++ b/app/composables/useApiFetch.ts @@ -0,0 +1,15 @@ +import { defu } from 'defu' + +export const useApiFetch = (request: string, options: Parameters[1] = {}) => { + const config = useRuntimeConfig() + const token = useCookie('auth_token') // Make sure this matches the cookie name you use on login + + const defaults: Parameters[1] = { + baseURL: config.public.api as string, + headers: token.value ? { Authorization: `Bearer ${token.value}` } : {}, + } + + const params = defu(options, defaults) + + return $fetch(request, params) +} \ No newline at end of file diff --git a/app/composables/useAuth.ts b/app/composables/useAuth.ts new file mode 100644 index 0000000..f5e1951 --- /dev/null +++ b/app/composables/useAuth.ts @@ -0,0 +1,49 @@ +import type { + ChangePasswordRequest, + CurrentUserResponse, EmailRequest, NotificationListResponse, + OkResponse, + OtpRequestResponse, PasswordLoginRequest, RegisterCitizenRequest, + RegisterCitizenResponse, RewardsResponse, + TokenResponse, VerifyOtpRequest +} from "~/types/api"; + +export const useAuth = () => { + const register = (body: RegisterCitizenRequest) => + useApiFetch('/api/v1/auth/register', { method: 'POST', body }) + + const requestOtp = (body: EmailRequest) => + useApiFetch('/api/v1/auth/otp/request', { method: 'POST', body }) + + const verifyOtp = (body: VerifyOtpRequest) => + useApiFetch('/api/v1/auth/otp/verify', { method: 'POST', body }) + + const loginWithPassword = (body: PasswordLoginRequest) => + useApiFetch('/api/v1/auth/login/password', { method: 'POST', body }) + + const changePassword = (body: ChangePasswordRequest) => + useApiFetch('/api/v1/auth/change-password', { method: 'POST', body }) + + const fetchCurrentUser = () => + useApiFetch('/api/v1/me', { method: 'GET' }) + + const fetchRewards = (query?: { page?: number; per_page?: number }) => + useApiFetch('/api/v1/me/rewards', { method: 'GET', query }) + + const fetchNotifications = (query?: { page?: number; per_page?: number }) => + useApiFetch('/api/v1/notifications', { method: 'GET', query }) + + const markNotificationRead = (id: number) => + useApiFetch(`/api/v1/notifications/${id}/read`, { method: 'PATCH' }) + + return { + register, + requestOtp, + verifyOtp, + loginWithPassword, + changePassword, + fetchCurrentUser, + fetchRewards, + fetchNotifications, + markNotificationRead, + } +} \ No newline at end of file diff --git a/app/composables/useMembers.ts b/app/composables/useMembers.ts new file mode 100644 index 0000000..394b8be --- /dev/null +++ b/app/composables/useMembers.ts @@ -0,0 +1,27 @@ +import { computed } from 'vue'; + +export interface Member { + name: string; + image: string; +} + +export function useMembers() { + const members: Member[] = [ + { name: "Renato Loiacono", image: "https://placehold.co/50x50" }, + { name: "Michelangelo Parisi", image: "https://placehold.co/50x50" }, + { name: "Gabriele Schiraldi", image: "https://placehold.co/50x50" }, + ]; + + const sortedMembers = computed(() => { + return [...members].sort((a, b) => { + const aSurnameInitial = a.name.split(" ").pop()?.[0] ?? ""; + const bSurnameInitial = b.name.split(" ").pop()?.[0] ?? ""; + return aSurnameInitial.localeCompare(bSurnameInitial); + }); + }); + + return { + members, + sortedMembers + }; +} \ No newline at end of file diff --git a/app/composables/useOperator.ts b/app/composables/useOperator.ts new file mode 100644 index 0000000..713a9bc --- /dev/null +++ b/app/composables/useOperator.ts @@ -0,0 +1,40 @@ +import type { + AssignTeamRequest, + InterventionSummaryResponse, + OkResponse, + PagedReportListResponse, + UpdateStatusRequest +} from "~/types/api"; + +export const useOperator = () => { + const getOpenReports = (query?: { page?: number; per_page?: number }) => + useApiFetch('/api/v1/operator/reports/open', { method: 'GET', query }) + + const getAssignedReports = (query?: { page?: number; per_page?: number }) => + useApiFetch('/api/v1/operator/reports/assigned', { method: 'GET', query }) + + const getOtherOperatorReports = (query?: { page?: number; per_page?: number }) => + useApiFetch('/api/v1/operator/reports/others', { method: 'GET', query }) + + const takeReport = (id: number) => + useApiFetch(`/api/v1/reports/${id}/take`, { method: 'POST' }) + + const updateReportStatus = (id: number, body: UpdateStatusRequest) => + useApiFetch(`/api/v1/reports/${id}/status`, { method: 'PATCH', body }) + + const assignTeam = (id: number, body: AssignTeamRequest) => + useApiFetch(`/api/v1/reports/${id}/assignments`, { method: 'POST', body }) + + const getInterventionSummary = (id: number) => + useApiFetch(`/api/v1/reports/${id}/intervention-summary`, { method: 'GET' }) + + return { + getOpenReports, + getAssignedReports, + getOtherOperatorReports, + takeReport, + updateReportStatus, + assignTeam, + getInterventionSummary, + } +} \ No newline at end of file diff --git a/app/composables/usePublic.ts b/app/composables/usePublic.ts new file mode 100644 index 0000000..0291702 --- /dev/null +++ b/app/composables/usePublic.ts @@ -0,0 +1,8 @@ +import type { OpenDataReportListResponse } from "~/types/api"; + +export default function usePublic() { + const getOpenDataReports = (query?: { page?: number; per_page?: number }) => + useApiFetch('/api/v1/open-data/reports', { method: 'GET', query }) + + return { getOpenDataReports } +} \ No newline at end of file diff --git a/app/composables/useReports.ts b/app/composables/useReports.ts new file mode 100644 index 0000000..be90186 --- /dev/null +++ b/app/composables/useReports.ts @@ -0,0 +1,49 @@ +import type { + CreateReportRequest, + CreateReportResponse, FeedbackRequest, FlagRequest, FlagResponse, + MediaUploadResponse, + MessageListResponse, MessageRequest, OkResponse, + ReportDetailResponse, + ReportListResponse +} from "~/types/api"; + +export const useReports = () => { + const getReports = (query?: { area_id?: number; category_id?: number; status?: string }) => + useApiFetch('/api/v1/reports', { method: 'GET', query }) + + const createReport = (body: CreateReportRequest) => + useApiFetch('/api/v1/reports', { method: 'POST', body }) + + const getReportDetail = (id: number) => + useApiFetch(`/api/v1/reports/${id}`, { method: 'GET' }) + + const uploadMedia = (id: number, formData: FormData) => + useApiFetch(`/api/v1/reports/${id}/media`, { method: 'POST', body: formData }) + + const getMessages = (id: number) => + useApiFetch(`/api/v1/reports/${id}/messages`, { method: 'GET' }) + + const addMessage = (id: number, body: MessageRequest) => + useApiFetch(`/api/v1/reports/${id}/messages`, { method: 'POST', body }) + + const addFeedback = (id: number, body: FeedbackRequest) => + useApiFetch(`/api/v1/reports/${id}/feedback`, { method: 'POST', body }) + + const flagReport = (id: number, body: FlagRequest) => + useApiFetch(`/api/v1/reports/${id}/flags`, { method: 'POST', body }) + + const flagMessage = (reportId: number, messageId: number, body: FlagRequest) => + useApiFetch(`/api/v1/reports/${reportId}/messages/${messageId}/flags`, { method: 'POST', body }) + + return { + getReports, + createReport, + getReportDetail, + uploadMedia, + getMessages, + addMessage, + addFeedback, + flagReport, + flagMessage, + } +} \ No newline at end of file