From 0ffcfdf6db1868f2378050e43facfd291a25fe3d Mon Sep 17 00:00:00 2001 From: jonrxu Date: Sun, 13 Oct 2024 16:45:55 -0400 Subject: [PATCH 1/2] feat(sublet): add FE apis and interfaces --- frontend/api/sublet/amenitiesApi.ts | 13 ++++ frontend/api/sublet/offersApi.ts | 39 +++++++++++ frontend/api/sublet/subletsApi.ts | 99 ++++++++++++++++++++++++++++ frontend/interfaces/sublet/Offer.ts | 18 +++++ frontend/interfaces/sublet/Sublet.ts | 74 +++++++++++++++++++++ 5 files changed, 243 insertions(+) create mode 100644 frontend/api/sublet/amenitiesApi.ts create mode 100644 frontend/api/sublet/offersApi.ts create mode 100644 frontend/api/sublet/subletsApi.ts create mode 100644 frontend/interfaces/sublet/Offer.ts create mode 100644 frontend/interfaces/sublet/Sublet.ts diff --git a/frontend/api/sublet/amenitiesApi.ts b/frontend/api/sublet/amenitiesApi.ts new file mode 100644 index 00000000..bfc89652 --- /dev/null +++ b/frontend/api/sublet/amenitiesApi.ts @@ -0,0 +1,13 @@ +// /api/amenitiesApi.ts + +import { doApiRequest } from '@/utils/fetch' + +const BASE_URL = 'api/sublet' + +export const getAmenities = async (): Promise => { + const response = await doApiRequest(`${BASE_URL}/listAmenities`) + if (!response.ok) { + throw new Error('Failed to fetch amenities') + } + return response.json() +} diff --git a/frontend/api/sublet/offersApi.ts b/frontend/api/sublet/offersApi.ts new file mode 100644 index 00000000..9d691365 --- /dev/null +++ b/frontend/api/sublet/offersApi.ts @@ -0,0 +1,39 @@ +// /api/offersApi.ts +import { CreateOfferRequest, OfferResponse } from '@/interfaces/sublet/Offer' +import { doApiRequest } from '@/utils/fetch' + +const BASE_URL = 'api/sublet' + +// Get all offers for a specific sublet +export const getOffers = async (subletId: string): Promise => { + const response = await doApiRequest(`${BASE_URL}/listOffers/${subletId}`) + if (!response.ok) { + throw new Error('Failed to fetch offers') + } + return response.json() +} + +// Create a new offer for a sublet +export const createOffer = async ( + subletId: string, + data: CreateOfferRequest +): Promise => { + const response = await doApiRequest(`${BASE_URL}/createOffer/${subletId}`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(data), + }) + if (!response.ok) { + throw new Error('Failed to create offer') + } +} + +// Delete an offer by sublet ID (no request body required) +export const deleteOffer = async (subletId: string): Promise => { + const response = await doApiRequest(`${BASE_URL}/destroyOffer/${subletId}`, { + method: 'DELETE', + }) + if (!response.ok) { + throw new Error('Failed to delete offer') + } +} diff --git a/frontend/api/sublet/subletsApi.ts b/frontend/api/sublet/subletsApi.ts new file mode 100644 index 00000000..871a7a99 --- /dev/null +++ b/frontend/api/sublet/subletsApi.ts @@ -0,0 +1,99 @@ +// /api/subletsApi.ts +import { + CreateSubletImageRequest, + CreateSubletRequest, + Sublet, + SubletResponse, + UpdateSubletRequest, +} from '@/interfaces/sublet/Sublet' +import { doApiRequest } from '@/utils/fetch' + +const BASE_URL = 'api/sublet' + +export const getSublets = async (): Promise => { + const response = await doApiRequest(`${BASE_URL}/listSublets`) + if (!response.ok) { + throw new Error('Failed to fetch sublets') + } + return response.json() +} + +export const getSubletById = async (id: number): Promise => { + const response = await doApiRequest( + `${BASE_URL}/retrieveSubletSerializerRead/${id}` + ) + if (!response.ok) { + throw new Error('Failed to fetch sublet') + } + return response.json() +} + +export const createSublet = async ( + data: CreateSubletRequest +): Promise => { + const response = await doApiRequest(`${BASE_URL}/createSublet`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(data), + }) + if (!response.ok) { + throw new Error('Failed to create sublet') + } + return response.json() +} + +export const updateSublet = async ( + id: string, + data: UpdateSubletRequest +): Promise => { + const response = await doApiRequest(`${BASE_URL}/updateSublet/${id}`, { + method: 'PUT', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(data), + }) + if (!response.ok) { + throw new Error('Failed to update sublet') + } + return response.json() +} + +export const deleteSublet = async (id: number): Promise => { + const response = await doApiRequest(`${BASE_URL}/destroySublet/${id}`, { + method: 'DELETE', + }) + if (!response.ok) { + throw new Error('Failed to delete sublet') + } +} + +export const uploadSubletImage = async ( + subletId: string, + data: CreateSubletImageRequest +): Promise => { + const formData = new FormData() + formData.append('sublet', data.sublet.toString()) + if (data.image) formData.append('image', data.image) + + const response = await doApiRequest( + `${BASE_URL}/createSubletImage/${subletId}`, + { + method: 'POST', + body: formData, + } + ) + if (!response.ok) { + throw new Error('Failed to upload sublet image') + } +} + +export const deleteSubletImage = async (imageId: number): Promise => { + const response = await doApiRequest( + `${BASE_URL}/destroySubletImage/${imageId}`, + { + method: 'DELETE', + } + ) + if (!response.ok) { + throw new Error('Failed to delete sublet image') + } +} diff --git a/frontend/interfaces/sublet/Offer.ts b/frontend/interfaces/sublet/Offer.ts new file mode 100644 index 00000000..a14134bd --- /dev/null +++ b/frontend/interfaces/sublet/Offer.ts @@ -0,0 +1,18 @@ +// /interfaces/CreateOfferRequest.ts +export interface CreateOfferRequest { + phone_number: string // Required phone number + email?: string | null // Optional email, max length 255 characters + message: string // Message, max length 255 characters + sublet: number // Sublet ID +} + +// /interfaces/OfferResponse.ts +export interface OfferResponse { + id: number // Offer ID + phone_number: string // Phone number of the user making the offer + email?: string | null // Optional email + message: string // Message content + created_date: string // ISO datetime string + user: string // User ID or name + sublet: number // Sublet ID associated with the offer +} diff --git a/frontend/interfaces/sublet/Sublet.ts b/frontend/interfaces/sublet/Sublet.ts new file mode 100644 index 00000000..35458bf3 --- /dev/null +++ b/frontend/interfaces/sublet/Sublet.ts @@ -0,0 +1,74 @@ +// SubletListing.ts + +export interface Sublet { + id: number + subletter: string // Name or ID of the subletter + amenities: string[] // Array of amenities as strings + title: string // Required, max length 255 characters + address?: string | null // Optional, max length 255 characters + beds?: number | null // Optional, integer + baths?: string | null // Optional, can be a decimal, e.g., "1.5" + description?: string | null // Optional description + external_link?: string | null // Optional external URL, must match a valid URL pattern + price: number // Required, integer value + negotiable: boolean // Indicates if the price is negotiable + start_date: string // Required, ISO 8601 date string + end_date: string // Required, ISO 8601 date string + expires_at: string // Required, ISO 8601 datetime string +} + +// /interfaces/SubletResponse.ts +export interface SubletResponse { + id: number + subletter: string // Subletter’s name or ID + amenities: string[] // List of amenities + title: string + address?: string | null // Optional or nullable + beds?: number | null // Optional number of beds + baths?: string | null // Optional, can be a decimal + description?: string | null // Optional description + external_link?: string | null // Optional external URL + price: number + negotiable: boolean // Is price negotiable? + start_date: string // ISO date string + end_date: string // ISO date string + expires_at: string // ISO datetime string +} + +// /interfaces/CreateSubletRequest.ts +export interface CreateSubletRequest { + amenities: string[] + title: string + address?: string | null + beds?: number | null + baths?: string | null + description?: string | null + external_link?: string | null + price: number + negotiable: boolean + start_date: string + end_date: string + expires_at: string +} + +// /interfaces/UpdateSubletRequest.ts +export interface UpdateSubletRequest { + amenities: string[] + title: string + address?: string | null + beds?: number | null + baths?: string | null + description?: string | null + external_link?: string | null + price: number + negotiable: boolean + start_date: string + end_date: string + expires_at: string +} + +// /interfaces/CreateSubletImageRequest.ts +export interface CreateSubletImageRequest { + sublet: number // Sublet ID + image: File | null // Binary image file +} From 328ad1fc066a5b27d1b5da0d70abb3e681220149 Mon Sep 17 00:00:00 2001 From: jonrxu Date: Sun, 20 Oct 2024 13:06:15 -0400 Subject: [PATCH 2/2] replacing throwing with log error --- frontend/api/sublet/amenitiesApi.ts | 3 ++- frontend/api/sublet/offersApi.ts | 15 ++++++++---- frontend/api/sublet/subletsApi.ts | 36 ++++++++++++++++++----------- 3 files changed, 35 insertions(+), 19 deletions(-) diff --git a/frontend/api/sublet/amenitiesApi.ts b/frontend/api/sublet/amenitiesApi.ts index bfc89652..af0cbb40 100644 --- a/frontend/api/sublet/amenitiesApi.ts +++ b/frontend/api/sublet/amenitiesApi.ts @@ -7,7 +7,8 @@ const BASE_URL = 'api/sublet' export const getAmenities = async (): Promise => { const response = await doApiRequest(`${BASE_URL}/listAmenities`) if (!response.ok) { - throw new Error('Failed to fetch amenities') + console.error('Failed to fetch amenities') + return [] } return response.json() } diff --git a/frontend/api/sublet/offersApi.ts b/frontend/api/sublet/offersApi.ts index 9d691365..9c237602 100644 --- a/frontend/api/sublet/offersApi.ts +++ b/frontend/api/sublet/offersApi.ts @@ -8,7 +8,8 @@ const BASE_URL = 'api/sublet' export const getOffers = async (subletId: string): Promise => { const response = await doApiRequest(`${BASE_URL}/listOffers/${subletId}`) if (!response.ok) { - throw new Error('Failed to fetch offers') + console.error('Failed to fetch offers') + return [] } return response.json() } @@ -17,23 +18,27 @@ export const getOffers = async (subletId: string): Promise => { export const createOffer = async ( subletId: string, data: CreateOfferRequest -): Promise => { +): Promise => { const response = await doApiRequest(`${BASE_URL}/createOffer/${subletId}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data), }) if (!response.ok) { - throw new Error('Failed to create offer') + console.error('Failed to create offer') + return false } + return true } // Delete an offer by sublet ID (no request body required) -export const deleteOffer = async (subletId: string): Promise => { +export const deleteOffer = async (subletId: string): Promise => { const response = await doApiRequest(`${BASE_URL}/destroyOffer/${subletId}`, { method: 'DELETE', }) if (!response.ok) { - throw new Error('Failed to delete offer') + console.error('Failed to delete offer') + return false } + return true } diff --git a/frontend/api/sublet/subletsApi.ts b/frontend/api/sublet/subletsApi.ts index 871a7a99..3e5cecd6 100644 --- a/frontend/api/sublet/subletsApi.ts +++ b/frontend/api/sublet/subletsApi.ts @@ -13,31 +13,34 @@ const BASE_URL = 'api/sublet' export const getSublets = async (): Promise => { const response = await doApiRequest(`${BASE_URL}/listSublets`) if (!response.ok) { - throw new Error('Failed to fetch sublets') + console.error('Failed to fetch sublets') + return [] } return response.json() } -export const getSubletById = async (id: number): Promise => { +export const getSubletById = async (id: number): Promise => { const response = await doApiRequest( `${BASE_URL}/retrieveSubletSerializerRead/${id}` ) if (!response.ok) { - throw new Error('Failed to fetch sublet') + console.error('Failed to fetch sublet') + return null } return response.json() } export const createSublet = async ( data: CreateSubletRequest -): Promise => { +): Promise => { const response = await doApiRequest(`${BASE_URL}/createSublet`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data), }) if (!response.ok) { - throw new Error('Failed to create sublet') + console.error('Failed to create sublet') + return null } return response.json() } @@ -45,31 +48,34 @@ export const createSublet = async ( export const updateSublet = async ( id: string, data: UpdateSubletRequest -): Promise => { +): Promise => { const response = await doApiRequest(`${BASE_URL}/updateSublet/${id}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data), }) if (!response.ok) { - throw new Error('Failed to update sublet') + console.error('Failed to update sublet') + return null } return response.json() } -export const deleteSublet = async (id: number): Promise => { +export const deleteSublet = async (id: number): Promise => { const response = await doApiRequest(`${BASE_URL}/destroySublet/${id}`, { method: 'DELETE', }) if (!response.ok) { - throw new Error('Failed to delete sublet') + console.error('Failed to delete sublet') + return false } + return true } export const uploadSubletImage = async ( subletId: string, data: CreateSubletImageRequest -): Promise => { +): Promise => { const formData = new FormData() formData.append('sublet', data.sublet.toString()) if (data.image) formData.append('image', data.image) @@ -82,11 +88,13 @@ export const uploadSubletImage = async ( } ) if (!response.ok) { - throw new Error('Failed to upload sublet image') + console.error('Failed to upload sublet image') + return false } + return true } -export const deleteSubletImage = async (imageId: number): Promise => { +export const deleteSubletImage = async (imageId: number): Promise => { const response = await doApiRequest( `${BASE_URL}/destroySubletImage/${imageId}`, { @@ -94,6 +102,8 @@ export const deleteSubletImage = async (imageId: number): Promise => { } ) if (!response.ok) { - throw new Error('Failed to delete sublet image') + console.error('Failed to delete sublet image') + return false } + return true }