feat: generate NSwag TypeScript client and authenticated API wrapper
This commit is contained in:
parent
40b256b870
commit
26e3efed81
75
src/AccountTracking.Web/nswag.json
Normal file
75
src/AccountTracking.Web/nswag.json
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
{
|
||||||
|
"runtime": "Default",
|
||||||
|
"defaultVariables": null,
|
||||||
|
"documentGenerator": {
|
||||||
|
"fromDocument": {
|
||||||
|
"url": "openapi.json",
|
||||||
|
"output": null,
|
||||||
|
"newLineBehavior": "Auto"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"codeGenerators": {
|
||||||
|
"openApiToTypeScriptClient": {
|
||||||
|
"className": "{controller}Client",
|
||||||
|
"moduleName": "",
|
||||||
|
"namespace": "",
|
||||||
|
"typeScriptVersion": 5.0,
|
||||||
|
"template": "Fetch",
|
||||||
|
"promiseType": "Promise",
|
||||||
|
"httpClass": "HttpClient",
|
||||||
|
"withCredentials": false,
|
||||||
|
"useSingletonProvider": false,
|
||||||
|
"injectionTokenType": "OpaqueToken",
|
||||||
|
"rxJsVersion": 6.0,
|
||||||
|
"dateTimeType": "String",
|
||||||
|
"nullValue": "Undefined",
|
||||||
|
"generateClientClasses": true,
|
||||||
|
"generateClientInterfaces": false,
|
||||||
|
"generateOptionalParameters": false,
|
||||||
|
"exportTypes": true,
|
||||||
|
"wrapDtoExceptions": false,
|
||||||
|
"exceptionClass": "SwaggerException",
|
||||||
|
"clientBaseClass": null,
|
||||||
|
"wrapResponses": false,
|
||||||
|
"wrapResponseMethods": [],
|
||||||
|
"generateResponseClasses": true,
|
||||||
|
"responseClass": "SwaggerResponse",
|
||||||
|
"protectedMethods": [],
|
||||||
|
"configurationClass": null,
|
||||||
|
"useTransformOptionsMethod": false,
|
||||||
|
"useTransformResultMethod": false,
|
||||||
|
"generateDtoTypes": true,
|
||||||
|
"operationGenerationMode": "MultipleClientsFromOperationId",
|
||||||
|
"includedOperationIds": [],
|
||||||
|
"excludedOperationIds": [],
|
||||||
|
"markOptionalProperties": true,
|
||||||
|
"generateCloneMethod": false,
|
||||||
|
"typeStyle": "Interface",
|
||||||
|
"enumStyle": "Enum",
|
||||||
|
"useLeafType": false,
|
||||||
|
"classTypes": [],
|
||||||
|
"extendedClasses": [],
|
||||||
|
"extensionCode": null,
|
||||||
|
"generateDefaultValues": true,
|
||||||
|
"excludedTypeNames": [],
|
||||||
|
"excludedParameterNames": [],
|
||||||
|
"handleReferences": false,
|
||||||
|
"generateTypeCheckFunctions": false,
|
||||||
|
"generateConstructorInterface": true,
|
||||||
|
"convertConstructorInterfaceData": false,
|
||||||
|
"importRequiredTypes": true,
|
||||||
|
"useGetBaseUrlMethod": false,
|
||||||
|
"baseUrlTokenName": "API_BASE_URL",
|
||||||
|
"queryNullValue": "",
|
||||||
|
"useAbortSignal": false,
|
||||||
|
"inlineNamedDictionaries": false,
|
||||||
|
"inlineNamedAny": false,
|
||||||
|
"includeHttpContext": false,
|
||||||
|
"templateDirectory": null,
|
||||||
|
"serviceHost": null,
|
||||||
|
"serviceSchemes": null,
|
||||||
|
"output": "src/api/apiClient.ts",
|
||||||
|
"newLineBehavior": "Auto"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
470
src/AccountTracking.Web/src/api/apiClient.ts
Normal file
470
src/AccountTracking.Web/src/api/apiClient.ts
Normal file
@ -0,0 +1,470 @@
|
|||||||
|
//----------------------
|
||||||
|
// <auto-generated>
|
||||||
|
// Generated using the NSwag toolchain v14.6.3.0 (NJsonSchema v11.5.2.0 (Newtonsoft.Json v13.0.0.0)) (http://NSwag.org)
|
||||||
|
// </auto-generated>
|
||||||
|
//----------------------
|
||||||
|
|
||||||
|
/* eslint-disable */
|
||||||
|
// ReSharper disable InconsistentNaming
|
||||||
|
|
||||||
|
export class AuthClient {
|
||||||
|
private http: { fetch(url: RequestInfo, init?: RequestInit): Promise<Response> };
|
||||||
|
private baseUrl: string;
|
||||||
|
protected jsonParseReviver: ((key: string, value: any) => any) | undefined = undefined;
|
||||||
|
|
||||||
|
constructor(baseUrl?: string, http?: { fetch(url: RequestInfo, init?: RequestInit): Promise<Response> }) {
|
||||||
|
this.http = http ? http : window as any;
|
||||||
|
this.baseUrl = baseUrl ?? "http://localhost:5099";
|
||||||
|
}
|
||||||
|
|
||||||
|
login(request: LoginRequest): Promise<LoginResponse> {
|
||||||
|
let url_ = this.baseUrl + "/api/auth/login";
|
||||||
|
url_ = url_.replace(/[?&]$/, "");
|
||||||
|
|
||||||
|
const content_ = JSON.stringify(request);
|
||||||
|
|
||||||
|
let options_: RequestInit = {
|
||||||
|
body: content_,
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Accept": "application/json"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.http.fetch(url_, options_).then((_response: Response) => {
|
||||||
|
return this.processLogin(_response);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected processLogin(response: Response): Promise<LoginResponse> {
|
||||||
|
const status = response.status;
|
||||||
|
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
|
||||||
|
if (status === 200) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
let result200: any = null;
|
||||||
|
result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as LoginResponse;
|
||||||
|
return result200;
|
||||||
|
});
|
||||||
|
} else if (status === 401) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
let result401: any = null;
|
||||||
|
result401 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as ProblemDetails;
|
||||||
|
return throwException("A server side error occurred.", status, _responseText, _headers, result401);
|
||||||
|
});
|
||||||
|
} else if (status !== 200 && status !== 204) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Promise.resolve<LoginResponse>(null as any);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class DashboardClient {
|
||||||
|
private http: { fetch(url: RequestInfo, init?: RequestInit): Promise<Response> };
|
||||||
|
private baseUrl: string;
|
||||||
|
protected jsonParseReviver: ((key: string, value: any) => any) | undefined = undefined;
|
||||||
|
|
||||||
|
constructor(baseUrl?: string, http?: { fetch(url: RequestInfo, init?: RequestInit): Promise<Response> }) {
|
||||||
|
this.http = http ? http : window as any;
|
||||||
|
this.baseUrl = baseUrl ?? "http://localhost:5099";
|
||||||
|
}
|
||||||
|
|
||||||
|
summary(year: number | undefined, month: number | null | undefined): Promise<SummaryDto> {
|
||||||
|
let url_ = this.baseUrl + "/api/dashboard/summary?";
|
||||||
|
if (year === null)
|
||||||
|
throw new globalThis.Error("The parameter 'year' cannot be null.");
|
||||||
|
else if (year !== undefined)
|
||||||
|
url_ += "year=" + encodeURIComponent("" + year) + "&";
|
||||||
|
if (month !== undefined && month !== null)
|
||||||
|
url_ += "month=" + encodeURIComponent("" + month) + "&";
|
||||||
|
url_ = url_.replace(/[?&]$/, "");
|
||||||
|
|
||||||
|
let options_: RequestInit = {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
"Accept": "application/json"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.http.fetch(url_, options_).then((_response: Response) => {
|
||||||
|
return this.processSummary(_response);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected processSummary(response: Response): Promise<SummaryDto> {
|
||||||
|
const status = response.status;
|
||||||
|
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
|
||||||
|
if (status === 200) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
let result200: any = null;
|
||||||
|
result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as SummaryDto;
|
||||||
|
return result200;
|
||||||
|
});
|
||||||
|
} else if (status !== 200 && status !== 204) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Promise.resolve<SummaryDto>(null as any);
|
||||||
|
}
|
||||||
|
|
||||||
|
spendingByCategory(year: number | undefined, month: number | null | undefined): Promise<CategorySpendingDto[]> {
|
||||||
|
let url_ = this.baseUrl + "/api/dashboard/spending-by-category?";
|
||||||
|
if (year === null)
|
||||||
|
throw new globalThis.Error("The parameter 'year' cannot be null.");
|
||||||
|
else if (year !== undefined)
|
||||||
|
url_ += "year=" + encodeURIComponent("" + year) + "&";
|
||||||
|
if (month !== undefined && month !== null)
|
||||||
|
url_ += "month=" + encodeURIComponent("" + month) + "&";
|
||||||
|
url_ = url_.replace(/[?&]$/, "");
|
||||||
|
|
||||||
|
let options_: RequestInit = {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
"Accept": "application/json"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.http.fetch(url_, options_).then((_response: Response) => {
|
||||||
|
return this.processSpendingByCategory(_response);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected processSpendingByCategory(response: Response): Promise<CategorySpendingDto[]> {
|
||||||
|
const status = response.status;
|
||||||
|
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
|
||||||
|
if (status === 200) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
let result200: any = null;
|
||||||
|
result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as CategorySpendingDto[];
|
||||||
|
return result200;
|
||||||
|
});
|
||||||
|
} else if (status !== 200 && status !== 204) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Promise.resolve<CategorySpendingDto[]>(null as any);
|
||||||
|
}
|
||||||
|
|
||||||
|
monthlyBalances(year: number | undefined): Promise<MonthlyBalanceDto[]> {
|
||||||
|
let url_ = this.baseUrl + "/api/dashboard/monthly-balances?";
|
||||||
|
if (year === null)
|
||||||
|
throw new globalThis.Error("The parameter 'year' cannot be null.");
|
||||||
|
else if (year !== undefined)
|
||||||
|
url_ += "year=" + encodeURIComponent("" + year) + "&";
|
||||||
|
url_ = url_.replace(/[?&]$/, "");
|
||||||
|
|
||||||
|
let options_: RequestInit = {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
"Accept": "application/json"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.http.fetch(url_, options_).then((_response: Response) => {
|
||||||
|
return this.processMonthlyBalances(_response);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected processMonthlyBalances(response: Response): Promise<MonthlyBalanceDto[]> {
|
||||||
|
const status = response.status;
|
||||||
|
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
|
||||||
|
if (status === 200) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
let result200: any = null;
|
||||||
|
result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as MonthlyBalanceDto[];
|
||||||
|
return result200;
|
||||||
|
});
|
||||||
|
} else if (status !== 200 && status !== 204) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Promise.resolve<MonthlyBalanceDto[]>(null as any);
|
||||||
|
}
|
||||||
|
|
||||||
|
cumulativeSpending(year: number | undefined, month: number | undefined): Promise<CumulativeSpendingDto[]> {
|
||||||
|
let url_ = this.baseUrl + "/api/dashboard/cumulative-spending?";
|
||||||
|
if (year === null)
|
||||||
|
throw new globalThis.Error("The parameter 'year' cannot be null.");
|
||||||
|
else if (year !== undefined)
|
||||||
|
url_ += "year=" + encodeURIComponent("" + year) + "&";
|
||||||
|
if (month === null)
|
||||||
|
throw new globalThis.Error("The parameter 'month' cannot be null.");
|
||||||
|
else if (month !== undefined)
|
||||||
|
url_ += "month=" + encodeURIComponent("" + month) + "&";
|
||||||
|
url_ = url_.replace(/[?&]$/, "");
|
||||||
|
|
||||||
|
let options_: RequestInit = {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
"Accept": "application/json"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.http.fetch(url_, options_).then((_response: Response) => {
|
||||||
|
return this.processCumulativeSpending(_response);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected processCumulativeSpending(response: Response): Promise<CumulativeSpendingDto[]> {
|
||||||
|
const status = response.status;
|
||||||
|
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
|
||||||
|
if (status === 200) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
let result200: any = null;
|
||||||
|
result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as CumulativeSpendingDto[];
|
||||||
|
return result200;
|
||||||
|
});
|
||||||
|
} else if (status !== 200 && status !== 204) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Promise.resolve<CumulativeSpendingDto[]>(null as any);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class TransactionsClient {
|
||||||
|
private http: { fetch(url: RequestInfo, init?: RequestInit): Promise<Response> };
|
||||||
|
private baseUrl: string;
|
||||||
|
protected jsonParseReviver: ((key: string, value: any) => any) | undefined = undefined;
|
||||||
|
|
||||||
|
constructor(baseUrl?: string, http?: { fetch(url: RequestInfo, init?: RequestInit): Promise<Response> }) {
|
||||||
|
this.http = http ? http : window as any;
|
||||||
|
this.baseUrl = baseUrl ?? "http://localhost:5099";
|
||||||
|
}
|
||||||
|
|
||||||
|
import(file: FileParameter | null | undefined): Promise<ImportResult> {
|
||||||
|
let url_ = this.baseUrl + "/api/transactions/import";
|
||||||
|
url_ = url_.replace(/[?&]$/, "");
|
||||||
|
|
||||||
|
const content_ = new FormData();
|
||||||
|
if (file !== null && file !== undefined)
|
||||||
|
content_.append("file", file.data, file.fileName ? file.fileName : "file");
|
||||||
|
|
||||||
|
let options_: RequestInit = {
|
||||||
|
body: content_,
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Accept": "application/json"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.http.fetch(url_, options_).then((_response: Response) => {
|
||||||
|
return this.processImport(_response);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected processImport(response: Response): Promise<ImportResult> {
|
||||||
|
const status = response.status;
|
||||||
|
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
|
||||||
|
if (status === 200) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
let result200: any = null;
|
||||||
|
result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as ImportResult;
|
||||||
|
return result200;
|
||||||
|
});
|
||||||
|
} else if (status === 400) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
let result400: any = null;
|
||||||
|
result400 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as ErrorResult;
|
||||||
|
return throwException("A server side error occurred.", status, _responseText, _headers, result400);
|
||||||
|
});
|
||||||
|
} else if (status !== 200 && status !== 204) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Promise.resolve<ImportResult>(null as any);
|
||||||
|
}
|
||||||
|
|
||||||
|
list(year: number | undefined, month: number | null | undefined, category: string | null | undefined, search: string | null | undefined, page: number | undefined, pageSize: number | undefined): Promise<TransactionListResponse> {
|
||||||
|
let url_ = this.baseUrl + "/api/transactions?";
|
||||||
|
if (year === null)
|
||||||
|
throw new globalThis.Error("The parameter 'year' cannot be null.");
|
||||||
|
else if (year !== undefined)
|
||||||
|
url_ += "year=" + encodeURIComponent("" + year) + "&";
|
||||||
|
if (month !== undefined && month !== null)
|
||||||
|
url_ += "month=" + encodeURIComponent("" + month) + "&";
|
||||||
|
if (category !== undefined && category !== null)
|
||||||
|
url_ += "category=" + encodeURIComponent("" + category) + "&";
|
||||||
|
if (search !== undefined && search !== null)
|
||||||
|
url_ += "search=" + encodeURIComponent("" + search) + "&";
|
||||||
|
if (page === null)
|
||||||
|
throw new globalThis.Error("The parameter 'page' cannot be null.");
|
||||||
|
else if (page !== undefined)
|
||||||
|
url_ += "page=" + encodeURIComponent("" + page) + "&";
|
||||||
|
if (pageSize === null)
|
||||||
|
throw new globalThis.Error("The parameter 'pageSize' cannot be null.");
|
||||||
|
else if (pageSize !== undefined)
|
||||||
|
url_ += "pageSize=" + encodeURIComponent("" + pageSize) + "&";
|
||||||
|
url_ = url_.replace(/[?&]$/, "");
|
||||||
|
|
||||||
|
let options_: RequestInit = {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
"Accept": "application/json"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.http.fetch(url_, options_).then((_response: Response) => {
|
||||||
|
return this.processList(_response);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected processList(response: Response): Promise<TransactionListResponse> {
|
||||||
|
const status = response.status;
|
||||||
|
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
|
||||||
|
if (status === 200) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
let result200: any = null;
|
||||||
|
result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as TransactionListResponse;
|
||||||
|
return result200;
|
||||||
|
});
|
||||||
|
} else if (status !== 200 && status !== 204) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Promise.resolve<TransactionListResponse>(null as any);
|
||||||
|
}
|
||||||
|
|
||||||
|
categories(): Promise<string[]> {
|
||||||
|
let url_ = this.baseUrl + "/api/transactions/categories";
|
||||||
|
url_ = url_.replace(/[?&]$/, "");
|
||||||
|
|
||||||
|
let options_: RequestInit = {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
"Accept": "application/json"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.http.fetch(url_, options_).then((_response: Response) => {
|
||||||
|
return this.processCategories(_response);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected processCategories(response: Response): Promise<string[]> {
|
||||||
|
const status = response.status;
|
||||||
|
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
|
||||||
|
if (status === 200) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
let result200: any = null;
|
||||||
|
result200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver) as string[];
|
||||||
|
return result200;
|
||||||
|
});
|
||||||
|
} else if (status !== 200 && status !== 204) {
|
||||||
|
return response.text().then((_responseText) => {
|
||||||
|
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Promise.resolve<string[]>(null as any);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LoginResponse {
|
||||||
|
token?: string;
|
||||||
|
expiresAt?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ProblemDetails {
|
||||||
|
type?: string | undefined;
|
||||||
|
title?: string | undefined;
|
||||||
|
status?: number | undefined;
|
||||||
|
detail?: string | undefined;
|
||||||
|
instance?: string | undefined;
|
||||||
|
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LoginRequest {
|
||||||
|
username?: string;
|
||||||
|
password?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SummaryDto {
|
||||||
|
totalSpent?: number;
|
||||||
|
totalIncome?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CategorySpendingDto {
|
||||||
|
category?: string;
|
||||||
|
total?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MonthlyBalanceDto {
|
||||||
|
month?: number;
|
||||||
|
closingBalance?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CumulativeSpendingDto {
|
||||||
|
day?: number;
|
||||||
|
cumulativeSpent?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ImportResult {
|
||||||
|
recordsImported?: number;
|
||||||
|
recordsSkipped?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ErrorResult {
|
||||||
|
error?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TransactionListResponse {
|
||||||
|
items?: TransactionDto[];
|
||||||
|
totalCount?: number;
|
||||||
|
page?: number;
|
||||||
|
pageSize?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TransactionDto {
|
||||||
|
id?: number;
|
||||||
|
bookingDate?: string;
|
||||||
|
counterPartyName?: string | undefined;
|
||||||
|
category?: string | undefined;
|
||||||
|
amount?: number;
|
||||||
|
balance?: number;
|
||||||
|
message?: string | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FileParameter {
|
||||||
|
data: any;
|
||||||
|
fileName: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SwaggerException extends Error {
|
||||||
|
override message: string;
|
||||||
|
status: number;
|
||||||
|
response: string;
|
||||||
|
headers: { [key: string]: any; };
|
||||||
|
result: any;
|
||||||
|
|
||||||
|
constructor(message: string, status: number, response: string, headers: { [key: string]: any; }, result: any) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.message = message;
|
||||||
|
this.status = status;
|
||||||
|
this.response = response;
|
||||||
|
this.headers = headers;
|
||||||
|
this.result = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected isSwaggerException = true;
|
||||||
|
|
||||||
|
static isSwaggerException(obj: any): obj is SwaggerException {
|
||||||
|
return obj.isSwaggerException === true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function throwException(message: string, status: number, response: string, headers: { [key: string]: any; }, result?: any): any {
|
||||||
|
if (result !== null && result !== undefined)
|
||||||
|
throw result;
|
||||||
|
else
|
||||||
|
throw new SwaggerException(message, status, response, headers, null);
|
||||||
|
}
|
||||||
27
src/AccountTracking.Web/src/api/index.ts
Normal file
27
src/AccountTracking.Web/src/api/index.ts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import { AuthClient, TransactionsClient, DashboardClient } from './apiClient'
|
||||||
|
|
||||||
|
// Custom fetch that injects the JWT and handles 401
|
||||||
|
class AuthFetch {
|
||||||
|
fetch(url: RequestInfo, init?: RequestInit): Promise<Response> {
|
||||||
|
const token = localStorage.getItem('token')
|
||||||
|
const headers = new Headers(init?.headers)
|
||||||
|
if (token) headers.set('Authorization', `Bearer ${token}`)
|
||||||
|
|
||||||
|
return fetch(url, { ...init, headers }).then((res) => {
|
||||||
|
if (res.status === 401) {
|
||||||
|
localStorage.removeItem('token')
|
||||||
|
localStorage.removeItem('expiresAt')
|
||||||
|
// Navigate to login — import router lazily to avoid circular dep
|
||||||
|
import('../router').then(({ default: router }) => router.push('/login'))
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const httpClient = new AuthFetch()
|
||||||
|
|
||||||
|
// Base URL is empty: NSwag generates full paths including /api/ prefix
|
||||||
|
export const authApi = new AuthClient('', httpClient)
|
||||||
|
export const transactionsApi = new TransactionsClient('', httpClient)
|
||||||
|
export const dashboardApi = new DashboardClient('', httpClient)
|
||||||
Loading…
Reference in New Issue
Block a user