diff --git a/package.json b/package.json index 3be6116..9b3f635 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "react-dom": "^18.2.0", "react-router-dom": "^6.4.3", "react-scripts": "5.0.1", + "reconnecting-eventsource": "^1.6.2", "typescript": "^4.9.3", "web-vitals": "^2.1.0" }, @@ -58,4 +59,4 @@ "last 1 safari version" ] } -} \ No newline at end of file +} diff --git a/src/utils/api/apiRequestHandler.ts b/src/utils/api/apiRequestHandler.ts index 8c84c44..39f8b47 100644 --- a/src/utils/api/apiRequestHandler.ts +++ b/src/utils/api/apiRequestHandler.ts @@ -1,8 +1,21 @@ -import { RegistrationRequest, AuthenticationSuccessResponse, LoginRequest, RefreshRequest } from "./types"; +import { + RegistrationRequest, + AuthenticationSuccessResponse, + LoginRequest, + RefreshRequest, + CreateTicketRequest, + CreateTicketResponse, + SendTicketMessageRequest, + GetTicketsRequest, + Ticket, + TicketMessage +} from "./types"; +import ReconnectingEventSource from "reconnecting-eventsource"; class ApiRequestHandler { private apiUrl: string; + private accessToken?: string; constructor(apiUrl: string) { this.apiUrl = apiUrl; @@ -21,6 +34,8 @@ class ApiRequestHandler { const result = await response.json(); if (result.error) return new Error(result.message); + this.accessToken = (result as AuthenticationSuccessResponse).accessToken; + return result as AuthenticationSuccessResponse; } catch (error) { return error as Error; @@ -39,6 +54,8 @@ class ApiRequestHandler { const result = await response.json(); if (result.error) return new Error(result.message); + this.accessToken = (result as AuthenticationSuccessResponse).accessToken; + return result as AuthenticationSuccessResponse; } catch (error) { return error as Error; @@ -67,12 +84,83 @@ class ApiRequestHandler { method: "POST", credentials: "include" }); - const result = await response.json(); - return result; + if (response.status !== 200) return new Error(`Unexpected status code. Expected: 200, received: ${response.status}`); // TODO correct success status code + + return null; } catch (error) { return error; } } + public async createTicket(request: CreateTicketRequest) { + try { + const response = await fetch(this.apiUrl + "support/create", { + method: "POST", + credentials: "include", + body: JSON.stringify(request), + headers: { + "Accept": "application/json, text/plain, */*", + "Content-Type": "application/json" + }, + }); + const result = await response.json(); + if (result.error) return new Error(result.message); + + return result as CreateTicketResponse; + } catch (error) { + return error as Error; + } + } + public subscribeToAllTickets(onMessage: (e: MessageEvent) => void, onError: (e: Event) => void) { + if (!this.accessToken) throw new Error("Trying to subscribe to SSE without access token"); + + const eventSource = new ReconnectingEventSource(`support/subscribe?Authorization=${this.accessToken}`); + eventSource.addEventListener("message", onMessage); + eventSource.addEventListener("error", onError); + } + public subscribeToTicket(ticketId: string, onMessage: (e: MessageEvent) => void, onError: (e: Event) => void) { + if (!this.accessToken) throw new Error("Trying to subscribe to SSE without access token"); + + const eventSource = new ReconnectingEventSource(`support/ticket?ticket=${ticketId}&Authorization=${this.accessToken}`); + eventSource.addEventListener("message", onMessage); + eventSource.addEventListener("error", onError); + } + public async sendTicketMessage(request: SendTicketMessageRequest) { + try { + const response = await fetch(this.apiUrl + "support/send", { + method: "POST", + credentials: "include", + body: JSON.stringify(request), + headers: { + "Accept": "application/json, text/plain, */*", + "Content-Type": "application/json" + }, + }); + if (response.status !== 200) return new Error(`Unexpected status code. Expected: 200, received: ${response.status}`); // TODO correct success status code + + return null; + } catch (error) { + return error as Error; + } + } + public async getTickets(request: GetTicketsRequest) { + try { + const response = await fetch(this.apiUrl + "support/getTickets", { + method: "POST", + credentials: "include", + body: JSON.stringify(request), + headers: { + "Accept": "application/json, text/plain, */*", + "Content-Type": "application/json" + }, + }); + const result = await response.json(); + if (result.error) return new Error(result.message); + + return result as Ticket[]; + } catch (error) { + return error as Error; + } + } } export const apiRequestHandler = new ApiRequestHandler("http://localhost:8080/"); \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 0c007c0..6249d3b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7858,6 +7858,11 @@ readdirp@~3.6.0: dependencies: picomatch "^2.2.1" +reconnecting-eventsource@^1.6.2: + version "1.6.2" + resolved "https://registry.yarnpkg.com/reconnecting-eventsource/-/reconnecting-eventsource-1.6.2.tgz#b7f5b03b1c76291f6fbcb0203004892a57ae253b" + integrity sha512-vHhoxVLbA2YcfljWMKEbgR1KVTgwIrnyh/bzVJc+gfQbGcUIToLL6jNhkUL4E+9FbnAcfUVNLIw2YCiliTg/4g== + recursive-readdir@^2.2.2: version "2.2.3" resolved "https://registry.yarnpkg.com/recursive-readdir/-/recursive-readdir-2.2.3.tgz#e726f328c0d69153bcabd5c322d3195252379372"