This commit is contained in:
Zeeshaun
2026-03-17 11:09:46 -05:00
parent bd1a9744ad
commit 6e7edcfe1b
332 changed files with 64174 additions and 0 deletions
@@ -0,0 +1,71 @@
export default class Routes {
public static Root(): string {
return "/";
}
public static Accounts(): string {
return this.Root() + this._account + "/";
}
public static Account(repoId: number): string {
return this.Accounts() + repoId + "/";
}
public static Admin(): string {
return this.Root() + "Admin/";
}
public static Reporting(): string {
return this.Root() + "Reporting/";
}
public static FloorCalculation(repoId: number, auctionAssignmentId: number): string {
return this.Account(repoId) + this._floorCalculation + "/" + auctionAssignmentId + "/";
}
public static FloorPricing(): string {
return this.Root() + "FloorPricing/";
}
public static AdminAuctionHouses(): string {
return this.Root() + "AuctionHouses/";
}
public static AdminAccountLookup(): string {
return this.Root() + "AccountLookup"
}
public static RepoIdKey(): string {
return "repoId";
}
public static Account_Decl(): string {
return this.Accounts() + this._RepoIdKey_Decl() + "/";
}
public static AuctionAssignmentIdKey(): string {
return "auctionAssignmentId";
}
public static FloorCalculation_Decl(): string {
return this.Account_Decl() + this._floorCalculation + "/" + this._AuctionAssignmentIdKey_Decl() + "/";
}
public static AdminRepoCompanies(): string {
return this.Root() + "RepoCompanies/";
}
private static _RepoIdKey_Decl(): string {
return ":" + this.RepoIdKey();
}
private static _AuctionAssignmentIdKey_Decl(): string {
return ":" + this.AuctionAssignmentIdKey();
}
private static _account = "Account";
private static _floorCalculation = "FloorCalculation";
}
@@ -0,0 +1,41 @@
import ArrayCalculations from "./ArrayCalculations";
describe('ArrayCalculations', () => {
it ('GetArrayIntersection() Returns Empty Array When an Empty Array is Passed', () => {
expect(ArrayCalculations.GetArrayIntersection([])).toEqual([]);
});
it ('GetArrayIntersection() Returns The Same Array When an Array of Length One (1) is Passed', () => {
expect(ArrayCalculations.GetArrayIntersection([[4,1,5,6]])).toEqual([4,1,5,6]);
});
it ('GetArrayIntersection() Returns Valid Intersection for Multiple Numerical Arrays', () => {
const intersection = ArrayCalculations.GetArrayIntersection([
[1,2,3,4,5,6,7,8,9],
[5,1],
[1,5,9],
[9,7,5,3,1],
]);
expect(intersection).toEqual([1,5]);
});
it ('GetArrayIntersection() Returns Valid Intersection for Multiple String Arrays', () => {
const intersection = ArrayCalculations.GetArrayIntersection([
['John', 'Abby', 'Chris'],
['Chris', 'Abby'],
['Abby']
]);
expect(intersection).toEqual(['Abby']);
});
it ('GetArrayIntersection() Returns Empty Array for Non-Overlapping Arrays', () => {
const intersection = ArrayCalculations.GetArrayIntersection([
[1,2,3,4,5,6,7,8,9],
[5,1],
[13,12,11]
]);
expect(intersection).toEqual([]);
});
});
@@ -0,0 +1,30 @@
class ArrayCalculations {
/**
* Create an array that represents the intersection of all arrays.
*
* @param arrays The arrays to intersection
*/
public static GetArrayIntersection<T>(arrays: T[][]): T[] {
if (!arrays.length) {
return [];
}
if (arrays.length === 1) {
return arrays[0];
}
var currentIntersection = arrays[0];
for (const arr of arrays) {
currentIntersection = this.GetIntersectionOfTwoArrays(currentIntersection, arr);
}
return currentIntersection;
}
private static GetIntersectionOfTwoArrays<T>(array1: T[], array2: T[]): T[] {
return array1.filter(cur => array2.indexOf(cur) !== -1);
}
}
export default ArrayCalculations;
@@ -0,0 +1,14 @@
import { Moment } from "moment";
export default class DateCalculations {
/**
* Calculate the absolute difference in days between two dates
*
* @param date1 The first date
* @param date2 The second date
*/
public static DayDifference(date1: Moment, date2: Moment): number {
const difference = date1.diff(date2, 'days');
return Math.abs(difference);
}
}
@@ -0,0 +1,43 @@
import devEnvironment from "../../environments/environment.dev";
import prodEnvironment from "../../environments/environment.prod";
import uatEnvironment from "../../environments/environment.uat";
const getConfigurationFromWindowLocation = () => {
const hostname = window.location.hostname;
if (hostname.match('localhost') || hostname.match('qa')) {
return devEnvironment;
}
if (hostname.match('uat')) {
return uatEnvironment;
}
return prodEnvironment;
}
const config = getConfigurationFromWindowLocation();
/**
* Static class for access application specific configuration data.
*/
export default class Configuration {
static get Get() {
return config;
}
static PrefixSSRSApiURL(relativeUrl: string){
return config.baseUrls.SSRSReportBaseUrl + relativeUrl;
}
static PrefixRepoApiUrl(relativeUrl: string) {
return config.baseUrls.repoApi + relativeUrl;
}
static PrefixCoreUrl(relativeUrl: string) {
return config.baseUrls.core + relativeUrl;
}
static PrefixCollectionsUrl(relativeUrl: string) {
return config.baseUrls.collections + relativeUrl;
}
}
@@ -0,0 +1,30 @@
import { Moment } from 'moment';
import moment from 'moment';
export default class DateConversions {
public static utcToMoment(utcDateTime?: string | Moment): Moment | undefined {
if (utcDateTime && utcDateTime !== '') {
return moment(utcDateTime);
}
}
public static momentToUTC(momentDate?: Moment): string | undefined {
if (momentDate) {
return momentDate.format();
}
}
public static momentToDate(momentDate?: Moment): Date | undefined {
if (momentDate) {
return momentDate.toDate();
}
}
public static dateToMoment(date: Date | null | undefined): Moment | undefined {
if (date) {
return moment(date);
}
}
}
@@ -0,0 +1,23 @@
import { NotificationBarType } from "../../components/notification-bar/NotificationBar";
enum AsyncState {
Inactive = 'Inactive',
Loading = 'Loading',
Success = 'Success',
Failure = 'Error',
}
export const mapAsyncStateToNotificationType = (asyncState: AsyncState): NotificationBarType => {
switch (asyncState) {
case AsyncState.Inactive:
return NotificationBarType.Info;
case AsyncState.Loading:
return NotificationBarType.Loading;
case AsyncState.Success:
return NotificationBarType.Success;
case AsyncState.Failure:
return NotificationBarType.Danger;
};
};
export default AsyncState;
@@ -0,0 +1,19 @@
import { AxiosError } from "axios";
import { isArray } from "util";
class AxiosMessageFormatting {
public static FormatError(error: AxiosError): string {
if (error.response && error.response.data) {
if (typeof error.response.data === 'string') {
return error.response.data;
} else if (isArray(error.response.data)) {
return error.response.data.reduce((prev, cur, i) => `${prev} (${i + 1}) ${cur}`, '');
}
}
return error.message;
}
}
export default AxiosMessageFormatting;
@@ -0,0 +1,24 @@
import moment, { Moment } from 'moment';
export default class DateFormatting {
public static FormatYYYYMMDD(date?: Moment) {
if (!date) {
return '';
}
return date.format('YYYY-MM-DD');
}
public static FormatMMDDYYYY(date?: Moment) {
if (!date) {
return '';
}
return date.format('MM/DD/YYYY');
}
public static FormatMMDDYYYHHMMA(date?: Moment) {
if (!date) {
return '';
}
return moment(date).format('MM/DD/YYYY - h:mm A');
}
}
@@ -0,0 +1,21 @@
export default class MonetaryFormatting {
private static _enUSDFormatter = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
minimumFractionDigits: 2,
});
/**
* Format a number into a 2-decimal-place USD Dollar representation
*
* @param num The number to format. null or undefined can reresent zero
*/
public static FormatUSD(num?: number): string {
if (!num) {
num = 0;
}
return MonetaryFormatting._enUSDFormatter.format(num);
}
}
@@ -0,0 +1,10 @@
class NumericalFormatting {
public static FormatPreciseFlooredNumber(num: number, precision: number) {
const decimalDigits = Math.pow(10, Math.floor(precision));
return Math.floor(num * decimalDigits) / decimalDigits;
}
}
export default NumericalFormatting;
@@ -0,0 +1,17 @@
export default class StringFormatting {
public static ToTitleCase(value?: string): string {
if (!value) {
return "";
}
return value.split(" ").map(
(x) => x ? x[0].toUpperCase() + x.substr(1).toLowerCase() : ""
).join(" ");
}
public static TrimLeft(value?: string): string {
if (!value) {
return "";
}
return value.trimStart();
}
}
@@ -0,0 +1,16 @@
import UrlFormatting from "./UrlFormatting";
describe('URL Formatting Class', () => {
it ('Replace URL Params', () => {
const replacedURL = UrlFormatting.ReplaceURLParams(
"http://www.test.com/foo/{fooId}/bar/{barId}/bool/{boolId}",
{ key: 'fooId', value: 1 },
{ key: 'barId', value: 'string' },
{ key: 'boolId', value: false },
);
expect(replacedURL).toEqual("http://www.test.com/foo/1/bar/string/bool/false");
})
});
@@ -0,0 +1,48 @@
interface IUrlParam {
key: string;
value: string | number | boolean;
}
export default class UrlFormatting {
/**
* Replace the variable parameters of a url with their values
*
* I.E.
*
* ReplaceURLParams(
* "http://www.test.com/foo/{fooId}/bar/{barId}",
* { key: 'fooId', value: 1 },
* { key: barId, value: 'second_param' }
* );
*
* Would result in a return value of:
* "http://www.test.com/foo/1/bar/second_param"
*
* NOTE: This method is case sensitive
*
* @param url The base URL
* @param params Each param with it's token and value
* @returns A paramterized version of the URL
*/
public static ReplaceURLParams(url: string, ...params: IUrlParam[]) {
for (const param of params) {
url = url.replace(`{${param.key}}`, param.value + '');
}
return url;
}
/**
* Concatenate the array value parameter items into a query string format to be added onto the end of a URL
*
* @param arrayValues The array of values for the query
* @param queryPrefix The string to be prepended to each array value
* @returns A query formatted URL substring
*/
public static FormatArrayValuesIntoQuery(arrayValues: string[], queryPrefix: string) {
let returnString = "";
for (const arrayValue of arrayValues) {
returnString += (queryPrefix + arrayValue);
}
return returnString;
}
}
@@ -0,0 +1,81 @@
import Axios, {AxiosError} from "axios";
import {toast} from "react-toastify";
import Configuration from "../configuration/Configuration";
import AxiosMessageFormatting from "../formatting/AxiosMessageFormatting";
import ToastDefaults from "../notifications/ToastDefaults";
interface IClientError {
name: string;
message: string;
stackTrace: string;
}
/**
* url: Provide the URL you were calling if available/relevant.
* action: Name the action you were taking to help a developer find where the error occurred. (Required)
* user: Provide a user if possible
* arguments Provide the arguments relevant to the action
*/
export interface LcuErrorContext {
url?: string;
action: string;
user?: string;
arguments?: any;
}
class ServerLogging {
public static ResolveErrorWithToast(err: AxiosError, context: LcuErrorContext) {
ServerLogging.ResolveError(err,context);
toast.error(AxiosMessageFormatting.FormatError(err), ToastDefaults.errorParams);
}
public static ResolveError(err: AxiosError, context: LcuErrorContext) {
if (!Configuration.Get.production) {
window.console.error(err);
window.console.error(context);
}
ServerLogging.LogError(err, context);
}
public static LogError(error: IClientError | AxiosError, context?: LcuErrorContext) {
let stackTrace: string = "";
if (this.isAxiosError(error)) {
stackTrace = error.stack || "Unknown";
} else {
stackTrace = error.stackTrace;
}
const clientError: IClientError = {
name: error.name,
message: error.message,
stackTrace: stackTrace
};
// We can do this without worry, the Stacktrace that arrives at the server is never a usable stacktrace
// and always looks like: at e.exports (https://qa-bsatool.lcu-internal.com/static/js/2.29bed6e0.chunk.js:2:1378526)
if (context) {
try {
clientError.stackTrace = JSON.stringify(context);
} catch (stringifyError) {
// This will happen if there is a circular reference or some other nonsense in arguments field.
context.arguments = "Arguments failed JSON.Stringify call";
clientError.stackTrace = JSON.stringify(context);
}
}
try {
Axios.post(Configuration.PrefixRepoApiUrl(Configuration.Get.urls.repoApi.logging), clientError);
} catch (err) {
window.console.error("Failed to log error to server.");
}
}
private static isAxiosError(error: IClientError | AxiosError): error is AxiosError {
return (error as AxiosError).stack !== undefined;
}
}
export default ServerLogging;
@@ -0,0 +1,17 @@
class ToastDefaults {
public static baseParams = {
autoClose: 3000,
hideProgressBar: true,
draggable: false
};
public static errorParams = {
autoClose: 5000,
hideProgressBar: true,
draggable: false
};
}
export default ToastDefaults;
@@ -0,0 +1,4 @@
export default interface IAlertGroup {
message: string;
repoIds: number[];
}
@@ -0,0 +1,12 @@
import AsyncState from "../enumerations/AsyncState";
interface IAsyncStateContainer<T> {
data?: T;
state: AsyncState;
}
export interface IAsyncStateContainerStrict<T> extends IAsyncStateContainer<T> {
data: T;
}
export default IAsyncStateContainer;
@@ -0,0 +1,4 @@
export interface IColumnSort {
index: number;
isReversed: boolean;
}
@@ -0,0 +1,8 @@
export interface IPagedResponse<T> {
items: T[];
totalItems: number;
currentPage: number;
totalPages: number;
nextPage?: string;
previousPage?: string;
}
@@ -0,0 +1,5 @@
import { IAlert } from '../../reducers/AlertReducer';
export default interface IState {
alerts: IAlert[];
}