diff options
| author | ivarlovlie <git@ivarlovlie.no> | 2022-10-05 14:45:21 +0200 |
|---|---|---|
| committer | ivarlovlie <git@ivarlovlie.no> | 2022-10-05 14:45:21 +0200 |
| commit | b7e39b59fd0fc7b5610ebff29035bf622079e0d8 (patch) | |
| tree | 64be84ebbdac9f7ceced983390c53b10d575af5c /old-apps/web-shared/src/lib | |
| parent | 2001c035fbb417ab0a3d42cfb04d17420bde4086 (diff) | |
| download | greatoffice-b7e39b59fd0fc7b5610ebff29035bf622079e0d8.tar.xz greatoffice-b7e39b59fd0fc7b5610ebff29035bf622079e0d8.zip | |
refactor: Change file structure
Diffstat (limited to 'old-apps/web-shared/src/lib')
31 files changed, 0 insertions, 1497 deletions
diff --git a/old-apps/web-shared/src/lib/api/internal-fetch.ts b/old-apps/web-shared/src/lib/api/internal-fetch.ts deleted file mode 100644 index 8659ccb..0000000 --- a/old-apps/web-shared/src/lib/api/internal-fetch.ts +++ /dev/null @@ -1,170 +0,0 @@ -import {Temporal} from "@js-temporal/polyfill"; -import {clear_session_data} from "$shared/lib/session"; -import {resolve_references} from "$shared/lib/helpers"; -import {replace} from "svelte-spa-router"; -import type {IInternalFetchResponse} from "$shared/lib/models/IInternalFetchResponse"; -import type {IInternalFetchRequest} from "$shared/lib/models/IInternalFetchRequest"; - -export async function http_post(url: string, body?: object|string, timeout = -1, skip_401_check = false, abort_signal: AbortSignal = undefined): Promise<IInternalFetchResponse> { - const init = { - method: "post", - } as RequestInit; - - if (abort_signal) { - init.signal = abort_signal; - } - - if (body) { - init.headers = { - "Content-Type": "application/json;charset=UTF-8", - }; - init.body = JSON.stringify(body); - } - - const response = await internal_fetch({url, init, timeout}); - const result = {} as IInternalFetchResponse; - - if (!skip_401_check && await is_401(response)) return result; - - result.ok = response.ok; - result.status = response.status; - result.http_response = response; - - if (response.status !== 204) { - try { - const ct = response.headers.get("Content-Type")?.toString() ?? ""; - if (ct.startsWith("application/json")) { - const data = await response.json(); - result.data = resolve_references(data); - } else if (ct.startsWith("text/plain")) { - const text = await response.text(); - result.data = text as string; - } - } catch { - // Ignored - } - } - - return result; -} - -export async function http_get(url: string, timeout = -1, skip_401_check = false, abort_signal: AbortSignal = undefined): Promise<IInternalFetchResponse> { - const init = { - method: "get", - } as RequestInit; - - if (abort_signal) { - init.signal = abort_signal; - } - - const response = await internal_fetch({url, init, timeout}); - const result = {} as IInternalFetchResponse; - - if (!skip_401_check && await is_401(response)) return result; - - result.ok = response.ok; - result.status = response.status; - result.http_response = response; - - if (response.status !== 204) { - try { - const ct = response.headers.get("Content-Type")?.toString() ?? ""; - if (ct.startsWith("application/json")) { - const data = await response.json(); - result.data = resolve_references(data); - } else if (ct.startsWith("text/plain")) { - const text = await response.text(); - result.data = text as string; - } - } catch { - // Ignored - } - } - - return result; -} - -export async function http_delete(url: string, body?: object|string, timeout = -1, skip_401_check = false, abort_signal: AbortSignal = undefined): Promise<IInternalFetchResponse> { - const init = { - method: "delete", - } as RequestInit; - - if (abort_signal) { - init.signal = abort_signal; - } - - if (body) { - init.headers = { - "Content-Type": "application/json;charset=UTF-8", - }; - init.body = JSON.stringify(body); - } - - const response = await internal_fetch({url, init, timeout}); - const result = {} as IInternalFetchResponse; - - if (!skip_401_check && await is_401(response)) return result; - - result.ok = response.ok; - result.status = response.status; - result.http_response = response; - - if (response.status !== 204) { - try { - const ct = response.headers.get("Content-Type")?.toString() ?? ""; - if (ct.startsWith("application/json")) { - const data = await response.json(); - result.data = resolve_references(data); - } else if (ct.startsWith("text/plain")) { - const text = await response.text(); - result.data = text as string; - } - } catch (error) { - // ignored - } - } - - return result; -} - -async function internal_fetch(request: IInternalFetchRequest): Promise<Response> { - if (!request.init) request.init = {}; - request.init.credentials = "include"; - request.init.headers = { - "X-TimeZone": Temporal.Now.timeZone().id, - ...request.init.headers - }; - - const fetch_request = new Request(request.url, request.init); - let response: any; - - try { - if (request.timeout > 500) { - response = await Promise.race([ - fetch(fetch_request), - new Promise((_, reject) => setTimeout(() => reject(new Error("Timeout")), request.timeout)) - ]); - } else { - response = await fetch(fetch_request); - } - } catch (error) { - if (error.message === "Timeout") { - console.error("Request timed out"); - } else if (error.message === "Network request failed") { - console.error("No internet connection"); - } else { - throw error; // rethrow other unexpected errors - } - } - - return response; -} - -async function is_401(response: Response): Promise<boolean> { - if (response.status === 401) { - clear_session_data(); - await replace("/login"); - return true; - } - return false; -} diff --git a/old-apps/web-shared/src/lib/api/root.ts b/old-apps/web-shared/src/lib/api/root.ts deleted file mode 100644 index d65efc4..0000000 --- a/old-apps/web-shared/src/lib/api/root.ts +++ /dev/null @@ -1,6 +0,0 @@ -import {http_post} from "$shared/lib/api/internal-fetch"; -import {api_base} from "$shared/lib/configuration"; - -export function server_log(message: string): void { - http_post(api_base("_/api/log"), message); -} diff --git a/old-apps/web-shared/src/lib/api/time-entry.ts b/old-apps/web-shared/src/lib/api/time-entry.ts deleted file mode 100644 index 064964a..0000000 --- a/old-apps/web-shared/src/lib/api/time-entry.ts +++ /dev/null @@ -1,84 +0,0 @@ -import {api_base} from "$shared/lib/configuration"; -import {is_guid} from "$shared/lib/helpers"; -import {http_delete, http_get, http_post} from "./internal-fetch"; -import type {TimeCategoryDto} from "$shared/lib/models/TimeCategoryDto"; -import type {TimeLabelDto} from "$shared/lib/models/TimeLabelDto"; -import type {TimeEntryDto} from "$shared/lib/models/TimeEntryDto"; -import type {TimeEntryQuery} from "$shared/lib/models/TimeEntryQuery"; -import type {IInternalFetchResponse} from "$shared/lib/models/IInternalFetchResponse"; - - -// ENTRIES - -export async function create_time_entry(payload: TimeEntryDto): Promise<IInternalFetchResponse> { - return http_post(api_base("v1/entries/create"), payload); -} - -export async function get_time_entry(entryId: string): Promise<IInternalFetchResponse> { - if (is_guid(entryId)) { - return http_get(api_base("v1/entries/" + entryId)); - } - throw new Error("entryId is not a valid guid."); -} - -export async function get_time_entries(entryQuery: TimeEntryQuery): Promise<IInternalFetchResponse> { - return http_post(api_base("v1/entries/query"), entryQuery); -} - -export async function delete_time_entry(id: string): Promise<IInternalFetchResponse> { - if (!is_guid(id)) throw new Error("id is not a valid guid"); - return http_delete(api_base("v1/entries/" + id + "/delete")); -} - -export async function update_time_entry(entryDto: TimeEntryDto): Promise<IInternalFetchResponse> { - if (!is_guid(entryDto.id ?? "")) throw new Error("id is not a valid guid"); - if (!entryDto.category) throw new Error("category is empty"); - if (!entryDto.stop) throw new Error("stop is empty"); - if (!entryDto.start) throw new Error("start is empty"); - return http_post(api_base("v1/entries/update"), entryDto); -} - -// LABELS -export async function create_time_label(labelDto: TimeLabelDto): Promise<IInternalFetchResponse> { - return http_post(api_base("v1/labels/create"), labelDto); -} - -export async function get_time_labels(): Promise<IInternalFetchResponse> { - return http_get(api_base("v1/labels")); -} - -export async function delete_time_label(id: string): Promise<IInternalFetchResponse> { - if (!is_guid(id)) throw new Error("id is not a valid guid"); - return http_delete(api_base("v1/labels/" + id + "/delete")); -} - -export async function update_time_label(labelDto: TimeLabelDto): Promise<IInternalFetchResponse> { - if (!is_guid(labelDto.id ?? "")) throw new Error("id is not a valid guid"); - if (!labelDto.name) throw new Error("name is empty"); - if (!labelDto.color) throw new Error("color is empty"); - return http_post(api_base("v1/labels/update"), labelDto); -} - - -// CATEGORIES -export async function create_time_category(category: TimeCategoryDto): Promise<IInternalFetchResponse> { - if (!category.name) throw new Error("name is empty"); - if (!category.color) throw new Error("color is empty"); - return http_post(api_base("v1/categories/create"), category); -} - -export async function get_time_categories(): Promise<IInternalFetchResponse> { - return http_get(api_base("v1/categories")); -} - -export async function delete_time_category(id: string): Promise<IInternalFetchResponse> { - if (!is_guid(id)) throw new Error("id is not a valid guid"); - return http_delete(api_base("v1/categories/" + id + "/delete")); -} - -export async function update_time_category(category: TimeCategoryDto): Promise<IInternalFetchResponse> { - if (!is_guid(category.id ?? "")) throw new Error("id is not a valid guid"); - if (!category.name) throw new Error("name is empty"); - if (!category.color) throw new Error("color is empty"); - return http_post(api_base("v1/categories/update"), category); -} diff --git a/old-apps/web-shared/src/lib/api/user.ts b/old-apps/web-shared/src/lib/api/user.ts deleted file mode 100644 index a3a149e..0000000 --- a/old-apps/web-shared/src/lib/api/user.ts +++ /dev/null @@ -1,47 +0,0 @@ -import {api_base} from "$shared/lib/configuration"; -import {http_delete, http_get, http_post} from "./internal-fetch"; -import type {LoginPayload} from "$shared/lib/models/LoginPayload"; -import type {UpdateProfilePayload} from "$shared/lib/models/UpdateProfilePayload"; -import type {CreateAccountPayload} from "$shared/lib/models/CreateAccountPayload"; -import type {IInternalFetchResponse} from "$shared/lib/models/IInternalFetchResponse"; - -export async function login(payload: LoginPayload): Promise<IInternalFetchResponse> { - return http_post(api_base("_/account/login"), payload); -} - -export async function logout(): Promise<IInternalFetchResponse> { - return http_get(api_base("_/account/logout")); -} - -export async function create_forgot_password_request(username: string): Promise<IInternalFetchResponse> { - if (!username) throw new Error("Username is empty"); - return http_get(api_base("_/forgot-password-requests/create?username=" + username)); -} - -export async function check_forgot_password_request(public_id: string): Promise<IInternalFetchResponse> { - if (!public_id) throw new Error("Id is empty"); - return http_get(api_base("_/forgot-password-requests/is-valid?id=" + public_id)); -} - -export async function fulfill_forgot_password_request(public_id: string, newPassword: string): Promise<IInternalFetchResponse> { - if (!public_id) throw new Error("Id is empty"); - return http_post(api_base("_/forgot-password-requests/fulfill"), {id: public_id, newPassword}); -} - -export async function delete_account(): Promise<IInternalFetchResponse> { - return http_delete(api_base("_/account/delete")); -} - -export async function update_profile(payload: UpdateProfilePayload): Promise<IInternalFetchResponse> { - if (!payload.password && !payload.username) throw new Error("Password and Username is empty"); - return http_post(api_base("_/account/update"), payload); -} - -export async function create_account(payload: CreateAccountPayload): Promise<IInternalFetchResponse> { - if (!payload.password && !payload.username) throw new Error("Password and Username is empty"); - return http_post(api_base("_/account/create"), payload); -} - -export async function get_profile_for_active_check(): Promise<IInternalFetchResponse> { - return http_get(api_base("_/account"), 0, true); -} diff --git a/old-apps/web-shared/src/lib/colors.ts b/old-apps/web-shared/src/lib/colors.ts deleted file mode 100644 index c2da03d..0000000 --- a/old-apps/web-shared/src/lib/colors.ts +++ /dev/null @@ -1,47 +0,0 @@ -export function generate_random_hex_color(skip_contrast_check = false) { - let hex = __generate_random_hex_color(); - if (skip_contrast_check) return hex; - while ((__calculate_contrast_ratio("#ffffff", hex) < 4.5) || (__calculate_contrast_ratio("#000000", hex) < 4.5)) { - hex = __generate_random_hex_color(); - } - - return hex; -} - -// Largely copied from chroma js api -function __generate_random_hex_color(): string { - let code = "#"; - for (let i = 0; i < 6; i++) { - code += "0123456789abcdef".charAt(Math.floor(Math.random() * 16)); - } - return code; -} - -function __calculate_contrast_ratio(hex1: string, hex2: string): number { - const rgb1 = __hex_to_rgb(hex1); - const rgb2 = __hex_to_rgb(hex2); - const l1 = __get_luminance(rgb1[0], rgb1[1], rgb1[2]); - const l2 = __get_luminance(rgb2[0], rgb2[1], rgb2[2]); - const result = l1 > l2 ? (l1 + 0.05) / (l2 + 0.05) : (l2 + 0.05) / (l1 + 0.05); - return result; -} - -function __hex_to_rgb(hex: string): number[] { - if (!hex.match(/^#([A-Fa-f0-9]{6})$/)) return []; - if (hex[0] === "#") hex = hex.substring(1, hex.length); - return [parseInt(hex.substring(0, 2), 16), parseInt(hex.substring(2, 4), 16), parseInt(hex.substring(4, 6), 16)]; -} - -function __get_luminance(r, g, b) { - // relative luminance - // see http://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef - r = __luminance_x(r); - g = __luminance_x(g); - b = __luminance_x(b); - return 0.2126 * r + 0.7152 * g + 0.0722 * b; -} - -function __luminance_x(x) { - x /= 255; - return x <= 0.03928 ? x / 12.92 : Math.pow((x + 0.055) / 1.055, 2.4); -} diff --git a/old-apps/web-shared/src/lib/configuration.ts b/old-apps/web-shared/src/lib/configuration.ts deleted file mode 100644 index eb38400..0000000 --- a/old-apps/web-shared/src/lib/configuration.ts +++ /dev/null @@ -1,78 +0,0 @@ -export const TOPBASEDOMAIN = "greatoffice.life"; -export const BASE_DOMAIN = "dev.greatoffice.life"; -export const DEV_BASE_DOMAIN = "localhost"; -export const API_ADDRESS = "https://api." + BASE_DOMAIN; -export const PROJECTS_ADDRESS = "https://projects." + BASE_DOMAIN; -export const PORTAL_ADDRESS = "https://portal." + BASE_DOMAIN; -export const FRONTPAGE_ADDRESS = "https://" + BASE_DOMAIN; -export const DEV_PORTAL_ADDRESS = "http://localhost:3001"; -export const DEV_FRONTPAGE_ADDRESS = "http://localhost:3002"; -export const DEV_API_ADDRESS = "http://localhost:5000"; -export const DEV_PROJECTS_ADDRESS = "http://localhost:3000"; -export const SECONDS_BETWEEN_SESSION_CHECK = 600; - -export function projects_base(path: string = ""): string { - return (is_development() ? DEV_PROJECTS_ADDRESS : PROJECTS_ADDRESS) + (path !== "" ? "/" + path : ""); -} - -export function base_domain(path: string = ""): string { - return (is_development() ? DEV_BASE_DOMAIN : TOPBASEDOMAIN) + (path !== "" ? "/" + path : ""); -} - -export function frontpage_base(path: string = ""): string { - return (is_development() ? DEV_FRONTPAGE_ADDRESS : FRONTPAGE_ADDRESS) + (path !== "" ? "/" + path : ""); -} - -export function portal_base(path: string = ""): string { - return (is_development() ? DEV_PORTAL_ADDRESS : PORTAL_ADDRESS) + (path !== "" ? "/" + path : ""); -} - -export function api_base(path: string = ""): string { - return (is_development() ? DEV_API_ADDRESS : API_ADDRESS) + (path !== "" ? "/" + path : ""); -} - -export function is_development(): boolean { - // @ts-ignore - return import.meta.env.DEV; -} - -export function is_debug(): boolean { - return localStorage.getItem(StorageKeys.debug) !== "true"; -} - -export const CookieNames = { - theme: "go_theme", - locale: "go_locale" -}; - -export const QueryKeys = { - labels: "labels", - categories: "categories", - entries: "entries", -}; - -export const IconNames = { - github: "github", - verticalDots: "verticalDots", - clock: "clock", - trash: "trash", - pencilSquare: "pencilSquare", - x: "x", - funnel: "funnel", - funnelFilled: "funnelFilled", - refresh: "refresh", - resetHard: "resetHard", - arrowUp: "arrowUp", - arrowDown: "arrowDown", - chevronDown: "chevronDown" -}; - -export const StorageKeys = { - session: "sessionData", - theme: "theme", - debug: "debug", - categories: "categories", - labels: "labels", - entries: "entries", - stopwatch: "stopwatchState" -}; diff --git a/old-apps/web-shared/src/lib/helpers.ts b/old-apps/web-shared/src/lib/helpers.ts deleted file mode 100644 index ad6f280..0000000 --- a/old-apps/web-shared/src/lib/helpers.ts +++ /dev/null @@ -1,491 +0,0 @@ -import { base_domain, CookieNames } from "$shared/lib/configuration"; -import { TimeEntryDto } from "$shared/lib/models/TimeEntryDto"; -import { UnwrappedEntryDateTime } from "$shared/lib/models/UnwrappedEntryDateTime"; -import { Temporal } from "@js-temporal/polyfill"; - -export const EMAIL_REGEX = new RegExp(/^([a-z0-9]+(?:([._\-])[a-z0-9]+)*@(?:[a-z0-9]+(?:(-)[a-z0-9]+)?\.)+[a-z0-9](?:[a-z0-9]*[a-z0-9])?)$/i); -export const URL_REGEX = new RegExp(/^(http:\/\/www\.|https:\/\/www\.|http:\/\/|https:\/\/)?[a-z0-9]+([\-.][a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?$/gm); -export const GUID_REGEX = new RegExp(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}$/i); -export const NORWEGIAN_PHONE_NUMBER_REGEX = new RegExp(/(0047|\+47|47)?\d{8,12}/); - -export function get_default_sorted(unsorted: Array<TimeEntryDto>): Array<TimeEntryDto> { - if (unsorted.length < 1) return unsorted; - const byStart = unsorted.sort((a, b) => { - return Temporal.Instant.compare(Temporal.Instant.from(b.start), Temporal.Instant.from(a.start)); - }); - - return byStart.sort((a, b) => { - return Temporal.Instant.compare(Temporal.Instant.from(b.stop), Temporal.Instant.from(a.stop)); - }); -} - -export function is_email(value: string): boolean { - return EMAIL_REGEX.test(String(value).toLowerCase()); -} - -export function is_url(value: string): boolean { - return URL_REGEX.test(String(value).toLowerCase()); -} - -export function is_norwegian_phone_number(value: string): boolean { - if (value.length < 8 || value.length > 12) { - return false; - } - return NORWEGIAN_PHONE_NUMBER_REGEX.test(String(value)); -} - -export function switch_theme() { - const html = document.querySelector("html"); - if (html.dataset.theme === "dark") { - html.dataset.theme = "light"; - } else { - html.dataset.theme = "dark"; - } - set_cookie(CookieNames.theme, html.dataset.theme, base_domain()); -} - -export function get_cookie(name) { - const value = `; ${document.cookie}`; - const parts = value.split(`; ${name}=`); - if (parts.length === 2) return parts.pop().split(";").shift(); -} - -export function set_cookie(name, value, baseDomain = window.location.host) { - document.cookie = name + "=" + encodeURIComponent(value) + (baseDomain ? ";domain=" + baseDomain : ""); -} - -export function unwrap_date_time_from_entry(entry: TimeEntryDto): UnwrappedEntryDateTime { - if (!entry) throw new Error("entry was undefined"); - const currentTimeZone = Temporal.Now.timeZone().id; - const startInstant = Temporal.Instant.from(entry.start).toZonedDateTimeISO(currentTimeZone); - const stopInstant = Temporal.Instant.from(entry.stop).toZonedDateTimeISO(currentTimeZone); - - return { - start_date: startInstant.toPlainDate(), - stop_date: stopInstant.toPlainDate(), - start_time: startInstant.toPlainTime(), - stop_time: stopInstant.toPlainTime(), - duration: Temporal.Duration.from({ - hours: stopInstant.hour, - minutes: stopInstant.minute - }).subtract(Temporal.Duration.from({ - hours: startInstant.hour, - minutes: startInstant.minute - })) - }; -} - - -export function is_guid(value: string): boolean { - if (!value) { - return false; - } - if (value[0] === "{") { - value = value.substring(1, value.length - 1); - } - return GUID_REGEX.test(value); -} - -export function is_empty_object(obj: object): boolean { - return obj !== void 0 && Object.keys(obj).length > 0; -} - -export function merge_obj_arr<T>(a: Array<T>, b: Array<T>, props: Array<string>): Array<T> { - let start = 0; - let merge = []; - - while (start < a.length) { - - if (a[start] === b[start]) { - //pushing the merged objects into array - merge.push({...a[start], ...b[start]}); - } - //incrementing start value - start = start + 1; - } - return merge; -} - -export function set_favicon(url: string) { - // Find the current favicon element - const favicon = document.querySelector("link[rel=\"icon\"]") as HTMLLinkElement; - if (favicon) { - // Update the new link - favicon.href = url; - } else { - // Create new `link` - const link = document.createElement("link"); - link.rel = "icon"; - link.href = url; - - // Append to the `head` element - document.head.appendChild(link); - } -} - -export function set_emoji_favicon(emoji: string) { - // Create a canvas element - const canvas = document.createElement("canvas"); - canvas.height = 64; - canvas.width = 64; - - // Get the canvas context - const context = canvas.getContext("2d") as CanvasRenderingContext2D; - context.font = "64px serif"; - context.fillText(emoji, 0, 64); - - // Get the custom URL - const url = canvas.toDataURL(); - - // Update the favicon - set_favicon(url); -} - - -// https://stackoverflow.com/a/48400665/11961742 -export function seconds_to_hour_minute_string(seconds: number, hourChar = "h", minuteChar = "m") { - const hours = Math.floor(seconds / (60 * 60)); - seconds -= hours * (60 * 60); - const minutes = Math.floor(seconds / 60); - return hours + "h" + minutes + "m"; -} - -export function seconds_to_hour_minute(seconds: number) { - const hours = Math.floor(seconds / (60 * 60)); - seconds -= hours * (60 * 60); - const minutes = Math.floor(seconds / 60); - return {hours, minutes}; -} - -export function get_query_string(params: any = {}): string { - const map = Object.keys(params).reduce((arr: Array<string>, key: string) => { - if (params[key] !== undefined) { - return arr.concat(`${key}=${encodeURIComponent(params[key])}`); - } - return arr; - }, [] as any); - - if (map.length) { - return `?${map.join("&")}`; - } - - return ""; -} - -export function make_url(url: string, params: object): string { - return `${url}${get_query_string(params)}`; -} - -export function load_script(url: string) { - unload_script(url, () => { - return new Promise(function (resolve, reject) { - const script = document.createElement("script"); - script.src = url; - - script.addEventListener("load", function () { - // The script is loaded completely - resolve(true); - }); - - document.body.appendChild(script); - }); - }); -} - -export function unload_script(src: string, callback?: Function): void { - document.querySelectorAll("script[src='" + src + "']").forEach(el => el.remove()); - if (typeof callback === "function") { - callback(); - } -} - -export function noop() { -} - -export async function run_async(functionToRun: Function): Promise<any> { - return new Promise((greatSuccess, graveFailure) => { - try { - greatSuccess(functionToRun()); - } catch (exception) { - graveFailure(exception); - } - }); -} - -// https://stackoverflow.com/a/45215694/11961742 -export function get_selected_options(domElement: HTMLSelectElement): Array<string> { - const ret = []; - - // fast but not universally supported - if (domElement.selectedOptions !== undefined) { - for (let i = 0; i < domElement.selectedOptions.length; i++) { - ret.push(domElement.selectedOptions[i].value); - } - - // compatible, but can be painfully slow - } else { - for (let i = 0; i < domElement.options.length; i++) { - if (domElement.options[i].selected) { - ret.push(domElement.options[i].value); - } - } - } - return ret; -} - -export function random_string(length: number): string { - if (!length) { - throw new Error("length is undefined"); - } - let result = ""; - const characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; - const charactersLength = characters.length; - for (let i = 0; i < length; i++) { - result += characters.charAt(Math.floor(Math.random() * charactersLength)); - } - return result; -} - -interface CreateElementOptions { - name: string, - properties?: object, - children?: Array<HTMLElement|Function|Node> -} - -export function create_element_from_object(elementOptions: CreateElementOptions): HTMLElement { - return create_element(elementOptions.name, elementOptions.properties, elementOptions.children); -} - -export function create_element(name: string, properties?: object, children?: Array<HTMLElement|any>): HTMLElement { - if (!name || name.length < 1) { - throw new Error("name is required"); - } - const node = document.createElement(name); - if (properties) { - for (const [key, value] of Object.entries(properties)) { - // @ts-ignore - node[key] = value; - } - } - - if (children && children.length > 0) { - let actualChildren = children; - if (typeof children === "function") { - // @ts-ignore - actualChildren = children(); - } - for (const child of actualChildren) { - node.appendChild(child as Node); - } - } - return node; -} - -export function get_element_position(element: HTMLElement|any) { - if (!element) return {x: 0, y: 0}; - let x = 0; - let y = 0; - while (true) { - x += element.offsetLeft; - y += element.offsetTop; - if (element.offsetParent === null) { - break; - } - element = element.offsetParent; - } - return {x, y}; -} - -export function restrict_input_to_numbers(element: HTMLElement, specials: Array<string> = [], mergeSpecialsWithDefaults: boolean = false): void { - if (element) { - element.addEventListener("keydown", (e) => { - const defaultSpecials = ["Backspace", "ArrowLeft", "ArrowRight", "Tab",]; - let keys = specials.length > 0 ? specials : defaultSpecials; - if (mergeSpecialsWithDefaults && specials) { - keys = [...specials, ...defaultSpecials]; - } - if (keys.indexOf(e.key) !== -1) { - return; - } - if (isNaN(parseInt(e.key))) { - e.preventDefault(); - } - }); - } -} - -export function element_has_focus(element: HTMLElement): boolean { - return element === document.activeElement; -} - -export function move_focus(element: HTMLElement): void { - if (!element) { - element = document.getElementsByTagName("body")[0]; - } - element.focus(); - // @ts-ignore - if (!element_has_focus(element)) { - element.setAttribute("tabindex", "-1"); - element.focus(); - } -} - -export function get_url_parameter(name: string): string { - // @ts-ignore - return new RegExp("[?&]" + name + "=([^&#]*)")?.exec(window.location.href)[1]; -} - -export function update_url_parameter(param: string, newVal: string): void { - let newAdditionalURL = ""; - let tempArray = location.href.split("?"); - const baseURL = tempArray[0]; - const additionalURL = tempArray[1]; - let temp = ""; - if (additionalURL) { - tempArray = additionalURL.split("&"); - for (let i = 0; i < tempArray.length; i++) { - if (tempArray[i].split("=")[0] !== param) { - newAdditionalURL += temp + tempArray[i]; - temp = "&"; - } - } - } - const rows_txt = temp + "" + param + "=" + newVal; - const newUrl = baseURL + "?" + newAdditionalURL + rows_txt; - window.history.replaceState("", "", newUrl); -} - - -export function get_style_string(rules: CSSRuleList) { - let styleString = ""; - for (const [key, value] of Object.entries(rules)) { - styleString += key + ":" + value + ";"; - } - return styleString; -} - -export function parse_iso_local(s: string) { - const b = s.split(/\D/); - //@ts-ignore - return new Date(b[0], b[1] - 1, b[2], b[3], b[4], b[5]); -} - -export function resolve_references(json: any) { - if (!json) return; - if (typeof json === "string") { - json = JSON.parse(json ?? "{}"); - } - const byid = {}, refs = []; - json = function recurse(obj, prop, parent) { - if (typeof obj !== "object" || !obj) { - return obj; - } - if (Object.prototype.toString.call(obj) === "[object Array]") { - for (let i = 0; i < obj.length; i++) { - if (typeof obj[i] !== "object" || !obj[i]) { - continue; - } else if ("$ref" in obj[i]) { - // @ts-ignore - obj[i] = recurse(obj[i], i, obj); - } else { - obj[i] = recurse(obj[i], prop, obj); - } - } - return obj; - } - if ("$ref" in obj) { - let ref = obj.$ref; - if (ref in byid) { - // @ts-ignore - return byid[ref]; - } - refs.push([parent, prop, ref]); - return; - } else if ("$id" in obj) { - let id = obj.$id; - delete obj.$id; - if ("$values" in obj) { - obj = obj.$values.map(recurse); - } else { - for (let prop2 in obj) { - // @ts-ignore - obj[prop2] = recurse(obj[prop2], prop2, obj); - } - } - // @ts-ignore - byid[id] = obj; - } - return obj; - }(json); - for (let i = 0; i < refs.length; i++) { - let ref = refs[i]; - // @ts-ignore - ref[0][ref[1]] = byid[ref[2]]; - } - return json; -} - -export function get_random_int(min: number, max: number): number { - min = Math.ceil(min); - max = Math.floor(max); - return Math.floor(Math.random() * (max - min + 1)) + min; -} - -export function to_readable_bytes(bytes: number): string { - const s = ["bytes", "kB", "MB", "GB", "TB", "PB"]; - const e = Math.floor(Math.log(bytes) / Math.log(1024)); - return (bytes / Math.pow(1024, e)).toFixed(2) + " " + s[e]; -} - -export function can_use_dom(): boolean { - return !!(typeof window !== "undefined" && window.document && window.document.createElement); -} - -export function session_storage_remove_regex(regex: RegExp): void { - let n = sessionStorage.length; - while (n--) { - const key = sessionStorage.key(n); - if (key && regex.test(key)) { - sessionStorage.removeItem(key); - } - } -} - -export function local_storage_remove_regex(regex: RegExp): void { - let n = localStorage.length; - while (n--) { - const key = localStorage.key(n); - if (key && regex.test(key)) { - localStorage.removeItem(key); - } - } -} - -export function session_storage_set_json(key: string, value: object): void { - sessionStorage.setItem(key, JSON.stringify(value)); -} - -export function session_storage_get_json(key: string): object { - return JSON.parse(sessionStorage.getItem(key) ?? "{}"); -} - -export function local_storage_set_json(key: string, value: object): void { - localStorage.setItem(key, JSON.stringify(value)); -} - -export function local_storage_get_json(key: string): object { - return JSON.parse(localStorage.getItem(key) ?? "{}"); -} - -export function get_hash_code(value: string): number|undefined { - let hash = 0; - if (value.length === 0) { - return; - } - for (let i = 0; i < value.length; i++) { - const char = value.charCodeAt(i); - hash = (hash << 5) - hash + char; - hash |= 0; - } - return hash; -} diff --git a/old-apps/web-shared/src/lib/i18n/en/index.ts b/old-apps/web-shared/src/lib/i18n/en/index.ts deleted file mode 100644 index 9db1759..0000000 --- a/old-apps/web-shared/src/lib/i18n/en/index.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type {BaseTranslation} from "../i18n-types"; - -const en: BaseTranslation = { - stopwatch: { - roundUp: "Round up", - roundDown: "Round down", - createEntry: "Create entry", - whatsYourFocus: "What's your focus?", - reset: "Reset", - start: "Start", - stop: "Stop", - }, - localeSwitcher: { - language: "Language" - } -}; - -export default en; diff --git a/old-apps/web-shared/src/lib/i18n/formatters.ts b/old-apps/web-shared/src/lib/i18n/formatters.ts deleted file mode 100644 index 78734f9..0000000 --- a/old-apps/web-shared/src/lib/i18n/formatters.ts +++ /dev/null @@ -1,11 +0,0 @@ -import type { FormattersInitializer } from 'typesafe-i18n' -import type { Locales, Formatters } from './i18n-types' - -export const initFormatters: FormattersInitializer<Locales, Formatters> = (locale: Locales) => { - - const formatters: Formatters = { - // add your formatter functions here - } - - return formatters -} diff --git a/old-apps/web-shared/src/lib/i18n/i18n-types.ts b/old-apps/web-shared/src/lib/i18n/i18n-types.ts deleted file mode 100644 index 62a13dd..0000000 --- a/old-apps/web-shared/src/lib/i18n/i18n-types.ts +++ /dev/null @@ -1,94 +0,0 @@ -// This file was auto-generated by 'typesafe-i18n'. Any manual changes will be overwritten. -/* eslint-disable */ -import type { BaseTranslation as BaseTranslationType, LocalizedString } from 'typesafe-i18n' - -export type BaseTranslation = BaseTranslationType -export type BaseLocale = 'en' - -export type Locales = - | 'en' - | 'nb' - -export type Translation = RootTranslation - -export type Translations = RootTranslation - -type RootTranslation = { - stopwatch: { - /** - * Round up - */ - roundUp: string - /** - * Round down - */ - roundDown: string - /** - * Create entry - */ - createEntry: string - /** - * What's your focus? - */ - whatsYourFocus: string - /** - * Reset - */ - reset: string - /** - * Start - */ - start: string - /** - * Stop - */ - stop: string - } - localeSwitcher: { - /** - * Language - */ - language: string - } -} - -export type TranslationFunctions = { - stopwatch: { - /** - * Round up - */ - roundUp: () => LocalizedString - /** - * Round down - */ - roundDown: () => LocalizedString - /** - * Create entry - */ - createEntry: () => LocalizedString - /** - * What's your focus? - */ - whatsYourFocus: () => LocalizedString - /** - * Reset - */ - reset: () => LocalizedString - /** - * Start - */ - start: () => LocalizedString - /** - * Stop - */ - stop: () => LocalizedString - } - localeSwitcher: { - /** - * Language - */ - language: () => LocalizedString - } -} - -export type Formatters = {} diff --git a/old-apps/web-shared/src/lib/i18n/i18n-util.async.ts b/old-apps/web-shared/src/lib/i18n/i18n-util.async.ts deleted file mode 100644 index 90e55a7..0000000 --- a/old-apps/web-shared/src/lib/i18n/i18n-util.async.ts +++ /dev/null @@ -1,27 +0,0 @@ -// This file was auto-generated by 'typesafe-i18n'. Any manual changes will be overwritten. -/* eslint-disable */ - -import { initFormatters } from './formatters' -import type { Locales, Translations } from './i18n-types.js' -import { loadedFormatters, loadedLocales, locales } from './i18n-util' - -const localeTranslationLoaders = { - en: () => import('./en/index.js'), - nb: () => import('./nb/index.js'), -} - -const updateDictionary = (locale: Locales, dictionary: Partial<Translations>) => - loadedLocales[locale] = { ...loadedLocales[locale], ...dictionary } - -export const loadLocaleAsync = async (locale: Locales): Promise<void> => { - updateDictionary( - locale, - (await localeTranslationLoaders[locale]()).default as unknown as Translations - ) - loadFormatters(locale) -} - -export const loadAllLocalesAsync = (): Promise<void[]> => Promise.all(locales.map(loadLocaleAsync)) - -export const loadFormatters = (locale: Locales): void => - void (loadedFormatters[locale] = initFormatters(locale)) diff --git a/old-apps/web-shared/src/lib/i18n/i18n-util.sync.ts b/old-apps/web-shared/src/lib/i18n/i18n-util.sync.ts deleted file mode 100644 index 8909831..0000000 --- a/old-apps/web-shared/src/lib/i18n/i18n-util.sync.ts +++ /dev/null @@ -1,27 +0,0 @@ -// This file was auto-generated by 'typesafe-i18n'. Any manual changes will be overwritten. -/* eslint-disable */ - -import { initFormatters } from './formatters' -import type { Locales, Translations } from './i18n-types.js' -import { loadedFormatters, loadedLocales, locales } from './i18n-util' - -import en from './en/index.js' -import nb from './nb/index.js' - -const localeTranslations = { - en, - nb, -} - -export const loadLocale = (locale: Locales): void => { - if (loadedLocales[locale]) return - - loadedLocales[locale] = localeTranslations[locale] as unknown as Translations - loadFormatters(locale) -} - -export const loadAllLocales = (): void => locales.forEach(loadLocale) - -export const loadFormatters = (locale: Locales): void => { - loadedFormatters[locale] = initFormatters(locale) -} diff --git a/old-apps/web-shared/src/lib/i18n/i18n-util.ts b/old-apps/web-shared/src/lib/i18n/i18n-util.ts deleted file mode 100644 index 5a9dd0d..0000000 --- a/old-apps/web-shared/src/lib/i18n/i18n-util.ts +++ /dev/null @@ -1,31 +0,0 @@ -// This file was auto-generated by 'typesafe-i18n'. Any manual changes will be overwritten. -/* eslint-disable */ - -import { i18n as initI18n, i18nObject as initI18nObject, i18nString as initI18nString } from 'typesafe-i18n' -import type { LocaleDetector } from 'typesafe-i18n/detectors' -import { detectLocale as detectLocaleFn } from 'typesafe-i18n/detectors' -import type { Formatters, Locales, Translations, TranslationFunctions } from './i18n-types.js' - -export const baseLocale: Locales = 'en' - -export const locales: Locales[] = [ - 'en', - 'nb' -] - -export const loadedLocales = {} as Record<Locales, Translations> - -export const loadedFormatters = {} as Record<Locales, Formatters> - -export const i18nString = (locale: Locales) => initI18nString<Locales, Formatters>(locale, loadedFormatters[locale]) - -export const i18nObject = (locale: Locales) => - initI18nObject<Locales, Translations, TranslationFunctions, Formatters>( - locale, - loadedLocales[locale], - loadedFormatters[locale] - ) - -export const i18n = () => initI18n<Locales, Translations, TranslationFunctions, Formatters>(loadedLocales, loadedFormatters) - -export const detectLocale = (...detectors: LocaleDetector[]) => detectLocaleFn<Locales>(baseLocale, locales, ...detectors) diff --git a/old-apps/web-shared/src/lib/i18n/nb/index.ts b/old-apps/web-shared/src/lib/i18n/nb/index.ts deleted file mode 100644 index a1d5f53..0000000 --- a/old-apps/web-shared/src/lib/i18n/nb/index.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type {Translation} from "../i18n-types"; - -const nb: Translation = { - stopwatch: { - roundUp: "Rund opp", - roundDown: "Rund ned", - createEntry: "Opprett tidsoppføring", - whatsYourFocus: "Hva skal du fokusere på?", - reset: "Tilbakestill", - start: "Start", - stop: "Stopp", - } -}; - -export default nb; diff --git a/old-apps/web-shared/src/lib/locale.ts b/old-apps/web-shared/src/lib/locale.ts deleted file mode 100644 index 002f874..0000000 --- a/old-apps/web-shared/src/lib/locale.ts +++ /dev/null @@ -1,20 +0,0 @@ -import {writable} from "svelte/store"; -import {base_domain, CookieNames} from "./configuration"; -import {get_cookie, set_cookie} from "./helpers"; - -export function preffered_or_default() { - if (/^en\b/i.test(navigator.language)) { - return "en"; - } - if (/^nb\b/i.test(navigator.language) || /^nn\b/i.test(navigator.language)) { - return "nb"; - } - return "en"; -} - -type Locales = "en"|"nb"; -export const currentLocale = writable<Locales>((get_cookie(CookieNames.locale) === "preffered" ? preffered_or_default() : get_cookie(CookieNames.locale) ?? preffered_or_default()) as Locales); -currentLocale.subscribe(locale => { - // @ts-ignore - set_cookie(CookieNames.locale, locale, base_domain()); -}); diff --git a/old-apps/web-shared/src/lib/models/CreateAccountPayload.ts b/old-apps/web-shared/src/lib/models/CreateAccountPayload.ts deleted file mode 100644 index d116308..0000000 --- a/old-apps/web-shared/src/lib/models/CreateAccountPayload.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface CreateAccountPayload { - username: string, - password: string -} diff --git a/old-apps/web-shared/src/lib/models/ErrorResult.ts b/old-apps/web-shared/src/lib/models/ErrorResult.ts deleted file mode 100644 index 7c70017..0000000 --- a/old-apps/web-shared/src/lib/models/ErrorResult.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface ErrorResult { - title: string, - text: string -} diff --git a/old-apps/web-shared/src/lib/models/IInternalFetchRequest.ts b/old-apps/web-shared/src/lib/models/IInternalFetchRequest.ts deleted file mode 100644 index 68505e2..0000000 --- a/old-apps/web-shared/src/lib/models/IInternalFetchRequest.ts +++ /dev/null @@ -1,6 +0,0 @@ -export interface IInternalFetchRequest { - url: string, - init?: RequestInit, - timeout?: number - retry_count?: number -} diff --git a/old-apps/web-shared/src/lib/models/IInternalFetchResponse.ts b/old-apps/web-shared/src/lib/models/IInternalFetchResponse.ts deleted file mode 100644 index 6c91b35..0000000 --- a/old-apps/web-shared/src/lib/models/IInternalFetchResponse.ts +++ /dev/null @@ -1,6 +0,0 @@ -export interface IInternalFetchResponse { - ok: boolean, - status: number, - data: any, - http_response: Response -} diff --git a/old-apps/web-shared/src/lib/models/ISession.ts b/old-apps/web-shared/src/lib/models/ISession.ts deleted file mode 100644 index f7ed46b..0000000 --- a/old-apps/web-shared/src/lib/models/ISession.ts +++ /dev/null @@ -1,7 +0,0 @@ -export interface ISession { - profile: { - username: string, - id: string, - }, - lastChecked: number, -}
\ No newline at end of file diff --git a/old-apps/web-shared/src/lib/models/IValidationResult.ts b/old-apps/web-shared/src/lib/models/IValidationResult.ts deleted file mode 100644 index 9a21b13..0000000 --- a/old-apps/web-shared/src/lib/models/IValidationResult.ts +++ /dev/null @@ -1,31 +0,0 @@ -export interface IValidationResult { - errors: Array<IValidationError>, - has_errors: Function, - add_error: Function, - remove_error: Function, -} - -export interface IValidationError { - _id?: string, - title: string, - text?: string -} - -export default class ValidationResult implements IValidationResult { - errors: IValidationError[] - has_errors(): boolean { - return this.errors?.length > 0; - } - add_error(prop: string, error: IValidationError): void { - if (!this.errors) this.errors = []; - error._id = prop; - this.errors.push(error); - } - remove_error(property: string): void { - const new_errors = []; - for (const error of this.errors) { - if (error._id != property) new_errors.push(error) - } - this.errors = new_errors; - } -} diff --git a/old-apps/web-shared/src/lib/models/LoginPayload.ts b/old-apps/web-shared/src/lib/models/LoginPayload.ts deleted file mode 100644 index ccd9bed..0000000 --- a/old-apps/web-shared/src/lib/models/LoginPayload.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface LoginPayload { - username: string, - password: string -} diff --git a/old-apps/web-shared/src/lib/models/TimeCategoryDto.ts b/old-apps/web-shared/src/lib/models/TimeCategoryDto.ts deleted file mode 100644 index 875e8cb..0000000 --- a/old-apps/web-shared/src/lib/models/TimeCategoryDto.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Temporal } from "@js-temporal/polyfill"; - -export interface TimeCategoryDto { - selected?: boolean; - id?: string, - modified_at?: Temporal.PlainDate, - name?: string, - color?: string -} diff --git a/old-apps/web-shared/src/lib/models/TimeEntryDto.ts b/old-apps/web-shared/src/lib/models/TimeEntryDto.ts deleted file mode 100644 index 71fe7a3..0000000 --- a/old-apps/web-shared/src/lib/models/TimeEntryDto.ts +++ /dev/null @@ -1,13 +0,0 @@ -import type { TimeLabelDto } from "./TimeLabelDto"; -import type { TimeCategoryDto } from "./TimeCategoryDto"; -import { Temporal } from "@js-temporal/polyfill"; - -export interface TimeEntryDto { - id: string, - modified_at?: Temporal.PlainDate, - start: string, - stop: string, - description: string, - labels?: Array<TimeLabelDto>, - category: TimeCategoryDto, -} diff --git a/old-apps/web-shared/src/lib/models/TimeEntryQuery.ts b/old-apps/web-shared/src/lib/models/TimeEntryQuery.ts deleted file mode 100644 index 6681c79..0000000 --- a/old-apps/web-shared/src/lib/models/TimeEntryQuery.ts +++ /dev/null @@ -1,27 +0,0 @@ -import type { TimeCategoryDto } from "./TimeCategoryDto"; -import type { TimeLabelDto } from "./TimeLabelDto"; -import type { Temporal } from "@js-temporal/polyfill"; - -export interface TimeEntryQuery { - duration: TimeEntryQueryDuration, - categories?: Array<TimeCategoryDto>, - labels?: Array<TimeLabelDto>, - dateRange?: TimeEntryQueryDateRange, - specificDate?: Temporal.PlainDateTime - page: number, - pageSize: number -} - -export interface TimeEntryQueryDateRange { - from: Temporal.PlainDateTime, - to: Temporal.PlainDateTime -} - -export enum TimeEntryQueryDuration { - TODAY = 0, - THIS_WEEK = 1, - THIS_MONTH = 2, - THIS_YEAR = 3, - SPECIFIC_DATE = 4, - DATE_RANGE = 5, -} diff --git a/old-apps/web-shared/src/lib/models/TimeLabelDto.ts b/old-apps/web-shared/src/lib/models/TimeLabelDto.ts deleted file mode 100644 index 2b42d07..0000000 --- a/old-apps/web-shared/src/lib/models/TimeLabelDto.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Temporal } from "@js-temporal/polyfill"; - -export interface TimeLabelDto { - id?: string, - modified_at?: Temporal.PlainDate, - name?: string, - color?: string -} diff --git a/old-apps/web-shared/src/lib/models/TimeQueryDto.ts b/old-apps/web-shared/src/lib/models/TimeQueryDto.ts deleted file mode 100644 index 607c51e..0000000 --- a/old-apps/web-shared/src/lib/models/TimeQueryDto.ts +++ /dev/null @@ -1,29 +0,0 @@ -import type { TimeEntryDto } from "./TimeEntryDto"; -import ValidationResult, { IValidationResult } from "./IValidationResult"; - -export interface ITimeQueryDto { - results: Array<TimeEntryDto>, - page: number, - pageSize: number, - totalRecords: number, - totalPageCount: number, - is_valid: Function -} - -export class TimeQueryDto implements ITimeQueryDto { - results: TimeEntryDto[]; - page: number; - pageSize: number; - totalRecords: number; - totalPageCount: number; - - is_valid(): IValidationResult { - const result = new ValidationResult(); - if (this.page < 0) { - result.add_error("page", { - title: "Page cannot be less than zero", - }) - } - return result; - } -} diff --git a/old-apps/web-shared/src/lib/models/UnwrappedEntryDateTime.ts b/old-apps/web-shared/src/lib/models/UnwrappedEntryDateTime.ts deleted file mode 100644 index e6022d8..0000000 --- a/old-apps/web-shared/src/lib/models/UnwrappedEntryDateTime.ts +++ /dev/null @@ -1,9 +0,0 @@ -import {Temporal} from "@js-temporal/polyfill"; - -export interface UnwrappedEntryDateTime { - start_date: Temporal.PlainDate, - stop_date: Temporal.PlainDate, - start_time: Temporal.PlainTime, - stop_time: Temporal.PlainTime, - duration: Temporal.Duration, -} diff --git a/old-apps/web-shared/src/lib/models/UpdateProfilePayload.ts b/old-apps/web-shared/src/lib/models/UpdateProfilePayload.ts deleted file mode 100644 index d2983ff..0000000 --- a/old-apps/web-shared/src/lib/models/UpdateProfilePayload.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface UpdateProfilePayload { - username?: string, - password?: string, -} diff --git a/old-apps/web-shared/src/lib/persistent-store.ts b/old-apps/web-shared/src/lib/persistent-store.ts deleted file mode 100644 index 922f3ab..0000000 --- a/old-apps/web-shared/src/lib/persistent-store.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { writable as _writable, readable as _readable, } from "svelte/store"; -import type { Writable, Readable, StartStopNotifier } from "svelte/store"; - -enum StoreType { - SESSION = 0, - LOCAL = 1 -} - -interface StoreOptions { - store?: StoreType; -} - -const default_store_options = { - store: StoreType.SESSION -} as StoreOptions; - -interface WritableStore<T> { - name: string, - initialState: T, - options?: StoreOptions -} - -interface ReadableStore<T> { - name: string, - initialState: T, - callback: StartStopNotifier<any>, - options?: StoreOptions -} - -function get_store(type: StoreType): Storage { - switch (type) { - case StoreType.SESSION: - return window.sessionStorage; - case StoreType.LOCAL: - return window.localStorage; - } -} - -function prepared_store_value(value: any): string { - try { - return JSON.stringify(value); - } catch (e) { - console.error(e); - return "__INVALID__"; - } -} - -function get_store_value<T>(options: WritableStore<T> | ReadableStore<T>): any { - try { - const storage = get_store(options.options.store); - const value = storage.getItem(options.name); - if (!value) return false; - return JSON.parse(value); - } catch (e) { - console.error(e); - return { __INVALID__: true }; - } -} - -function hydrate<T>(store: Writable<T>, options: WritableStore<T> | ReadableStore<T>): void { - const value = get_store_value<T>(options); - if (value && store.set) store.set(value); -} - -function subscribe<T>(store: Writable<T> | Readable<T>, options: WritableStore<T> | ReadableStore<T>): void { - const storage = get_store(options.options.store); - if (!store.subscribe) return; - store.subscribe((state: any) => { - storage.setItem(options.name, prepared_store_value(state)); - }); -} - -function writable_persistent<T>(options: WritableStore<T>): Writable<T> { - if (options.options === undefined) options.options = default_store_options; - console.log("Creating writable store with options: ", options); - const store = _writable<T>(options.initialState); - hydrate(store, options); - subscribe(store, options); - return store; -} - -function readable_persistent<T>(options: ReadableStore<T>): Readable<T> { - if (options.options === undefined) options.options = default_store_options; - console.log("Creating readable store with options: ", options); - const store = _readable<T>(options.initialState, options.callback); - // hydrate(store, options); - subscribe(store, options); - return store; -} - -export { - writable_persistent, - readable_persistent, - StoreType -}; - -export type { - WritableStore, - ReadableStore, - StoreOptions -}; - diff --git a/old-apps/web-shared/src/lib/session.ts b/old-apps/web-shared/src/lib/session.ts deleted file mode 100644 index f729687..0000000 --- a/old-apps/web-shared/src/lib/session.ts +++ /dev/null @@ -1,68 +0,0 @@ -import {Temporal} from "@js-temporal/polyfill"; -import {get_profile_for_active_check, logout} from "./api/user"; -import {is_guid, session_storage_get_json, session_storage_set_json} from "./helpers"; -import {SECONDS_BETWEEN_SESSION_CHECK, StorageKeys} from "./configuration"; -import type {ISession} from "$shared/lib/models/ISession"; - -export async function is_active(forceRefresh: boolean = false): Promise<boolean> { - const nowEpoch = Temporal.Now.instant().epochSeconds; - const data = session_storage_get_json(StorageKeys.session) as ISession; - const expiryEpoch = data?.lastChecked + SECONDS_BETWEEN_SESSION_CHECK; - const lastCheckIsStaleOrNone = !is_guid(data?.profile?.id) || (expiryEpoch < nowEpoch); - if (forceRefresh || lastCheckIsStaleOrNone) { - return await call_api(); - } else { - const sessionIsValid = data.profile && is_guid(data.profile.id); - if (!sessionIsValid) { - clear_session_data(); - console.log("Session data is not valid"); - } - return sessionIsValid; - } -} - -export async function end_session(cb: Function): Promise<void> { - await logout(); - clear_session_data(); - cb(); -} - -async function call_api(): Promise<boolean> { - console.log("Getting profile data while checking session state"); - try { - const response = await get_profile_for_active_check(); - if (response.ok) { - const userData = await response.data; - if (is_guid(userData.id) && userData.username) { - const session = { - profile: userData, - lastChecked: Temporal.Now.instant().epochSeconds - } as ISession; - session_storage_set_json(StorageKeys.session, session); - console.log("Successfully got profile data while checking session state"); - return true; - } else { - console.error("Api returned invalid data while getting profile data"); - clear_session_data(); - return false; - } - } else { - console.error("Api returned unsuccessfully while getting profile data"); - clear_session_data(); - return false; - } - } catch (e) { - console.error(e); - clear_session_data(); - return false; - } -} - -export function clear_session_data() { - session_storage_set_json(StorageKeys.session, {}); - console.log("Cleared session data."); -} - -export function get_session_data(): ISession { - return session_storage_get_json(StorageKeys.session) as ISession; -} |
