import { useState } from "react"; import { Buffer } from "buffer"; import { v4 as uuidv4 } from "uuid"; /** * constants */ //const wssProtocol = window.location.protocol === "https:" ? "wss://" : "ws://"; let dashboardAddress = ""; let apiAddress = ""; // let staticContentAddress = ""; // let wsAddress = ""; if (window.location.hostname === "localhost" && window.location.port === "") { // for docker container testing on localhost dashboardAddress = "http://localhost/"; apiAddress = "http://localhost/api/v1"; // staticContentAddress = "http://localhost/api/"; // wsAddress = "ws://localhost/ws"; } else if (window.location.hostname === "localhost") { // programming on localhost dashboardAddress = `http://localhost:${window.location.port}/`; apiAddress = "http://localhost:50128/api/v1"; // staticContentAddress = "http://localhost:50050/"; // wsAddress = "ws://localhost:50050/ws"; } else { // production dashboardAddress = `${window.location.protocol}//${window.location.hostname}/`; apiAddress = `${window.location.protocol}//${window.location.hostname}/api/v1`; //staticContentAddress = `${window.location.protocol}//${window.location.hostname}/api/`; // wsAddress = `${wssProtocol}${window.location.hostname}/ws`; } export const Constants = { APP_NAME: "ZeitAdler", TEXT_EMPTY_PLACEHOLDER: "-/-", DASHBOARD_ADDRESS: dashboardAddress, API_ADDRESS: apiAddress, //STATIC_CONTENT_ADDRESS: staticContentAddress, // WS_ADDRESS: wsAddress, EMBED_CALENDAR_ADDRESS: process.env.REACT_APP_EMBED_CALENDAR_ADDRESS, EMBED_CALENDAR_SCRIPT_ADDRESS: process.env.REACT_APP_EMBED_CALENDAR_SCRIPT_ADDRESS, PRIVACY_POLICY_URL: process.env.REACT_APP_PRIVACY_POLICY_URL, ROUTE_PATHS: { AUTHENTICATION: { LOGIN: "/login", SIGN_UP: "/buy", FORGOT_PASSWORD: "/forgot-password", CHECKOUT_SUCCESS: "/checkout/success", CHECKOUT_CANCELED: "/checkout/canceled", }, VERIFY: "/verify", OVERVIEW: "/", STORE: { // schema: /store/:storeId/:subPage OVERVIEW: "/store", SETTINGS: "settings", EMPLOYEES: "employees", SERVICES: "services", CALENDAR: "calendar", CALENDAR_AUTH: "calendar/auth", }, PAYMENT_PLAN: "payment-plan", FEEDBACK: "/feedback", SUPPORT: "/support", USER_PROFILE: "/user-profile", }, GLOBALS: { MIN_USERNAME_LENGTH: 3, MAX_USERNAME_LENGTH: 20, //MIN_ACCOUNT_NAME_LENGTH: 3, //MAX_ACCOUNT_NAME_LENGTH: 20, MIN_EMAIL_LENGTH: 3, MAX_EMAIL_LENGTH: 64, EMAIL_REGEX: /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/, MIN_PASSWORD_LENGTH: 8, MAX_PASSWORD_LENGTH: 64, MIN_STORE_SERVICE_NAME_LENGTH: 3, MAX_STORE_SERVICE_NAME_LENGTH: 64, MIN_STORE_SERVICE_ACTIVITY_NAME_LENGTH: 3, MAX_STORE_SERVICE_ACTIVITY_NAME_LENGTH: 64, MAX_STORE_SERVICE_ACTIVITY_DESCRIPTION_LENGTH: 1024, MIN_STORE_SERVICE_ACTIVITY_PRICE: 0, MAX_STORE_SERVICE_ACTIVITY_PRICE: 10000000, MIN_STORE_SERVICE_ACTIVITY_DURATION_MINUTES: 0, MAX_STORE_SERVICE_ACTIVITY_DURATION_MINUTES: 60 * 24, // 24 hours in minutes MIN_CALENDAR_FUTURE_BOOKING_DAYS: 1, MIN_CALENDAR_EARLIEST_BOOKING_TIME: 15, MAX_CALENDAR_EARLIEST_BOOKING_TIME: 60 * 24, // 24 hours in minutes MIN_FEEDBACK_LENGTH: 10, MAX_FEEDBACK_LENGTH: 1024, MIN_COMPANY_NAME_LENGTH: 3, MAX_COMPANY_NAME_LENGTH: 64, }, DELAY_EMAIL_CHECK: 250, CLARITY_PROJECT_ID: process.env.REACT_APP_CLARITY_PROJECT_ID, ACCOUNT_DELETED_AFTER_DAYS: 30, ACCOUNT_STATE: { ACTIVE: 0, PENDING_DELETION: 1, INIT_LOGGING: 2, BANNED: 3, PENDING_EMAIL_VERIFICATION: 4, }, SUPPORT_EMAIL: process.env.REACT_APP_SUPPORT_EMAIL, PAYMENT_PLAN: [ { name: "Demo", maxEmployees: 5, calendarMaxFutureBookingDays: 14, }, { name: "Basic", maxEmployees: 15, calendarMaxFutureBookingDays: 60, price: { en: { totalNet: "9,99 €", // netto vat: "1,90 €", totalAmount: "11,89 €", // brutto }, de: { totalNet: "9,99 €", vat: "1,90 €", totalAmount: "11,89 €", }, }, }, { name: "Premium", maxEmployees: 50, // temporary calendarMaxFutureBookingDays: 365, // temporary price: { en: { totalNet: "24,99 €", vat: "4,75 €", totalAmount: "29,74 €", }, de: { totalNet: "24,99 €", vat: "4,75 €", totalAmount: "29,74 €", }, }, }, ], }; export function isEmailValid(email) { return Constants.GLOBALS.EMAIL_REGEX.test(email); } export const AppStyle = { app: { margin: 12, }, colors: { primary: "#6878d6", }, }; export function GetUuid() { return uuidv4(); } /** * user session */ export function UseUserSession() { const getUserSession = () => { return getUserSessionFromLocalStorage(); }; const [userSession, setUserSession] = useState(getUserSession()); const saveUserSession = (session) => { setUserSession(session); if (session === undefined) { localStorage.removeItem("session"); } else { setUserSessionToLocalStorage(session); } }; return { setUserSession: saveUserSession, userSession, }; } export function getUserSessionFromLocalStorage() { return localStorage.getItem("session"); } export function setUserSessionToLocalStorage(session) { localStorage.setItem("session", session); } // needed for a user who uses multiple tabs in the browser // with the same session id because otherwise the last browser // tab would subscribe to the topic and the other tabs would // not receive any messages // used for topic subscribtion and grouptasks export const BrowserTabSession = GetUuid(); export const wsConnectionCustomEventName = "wsConnection"; // used for sideMenu export const BreakpointLgWidth = 992; export function EncodeStringToBase64(value) { return Buffer.from(value).toString("base64"); } export function DecodedBase64ToString(value) { return Buffer.from(value, "base64").toString(); } export const myFetchContentType = { JSON: 0, MULTIPART_FORM_DATA: 1, }; export function myFetch({ url, method, body = null, headers = {}, contentType = myFetchContentType.JSON, fetchUrl = Constants.API_ADDRESS, ignoreUnauthorized = false, notificationApi = null, t = null, }) { const getContentType = () => { if (contentType === myFetchContentType.JSON) return "application/json"; return "multipart/form-data"; }; const getBody = () => { if (!body) return null; if (contentType === myFetchContentType.JSON) return JSON.stringify(body); return body; }; // abort fetch if it takes to long const controller = new AbortController(); const signal = controller.signal; setTimeout(() => controller.abort(), 30000); // 30 seconds const requestOptions = { method: method, headers: { "X-Authorization": getUserSessionFromLocalStorage(), "Content-Type": getContentType(), ...headers, }, body: getBody(), signal: signal, }; if (fetchUrl === "") { fetchUrl = Constants.API_ADDRESS; } return fetch(`${fetchUrl}${url}`, requestOptions) .then((response) => { // if status is not in range 200-299 if (!response.ok) { if (!ignoreUnauthorized && response.status === 401) { console.error("Unauthorized"); // TODO: check here //setUserSessionToLocalStorage(""); //window.location.href = "/"; } throw response.status; } // check if response is json if (response.headers.get("content-type")?.includes("application/json")) { return response.json(); } return response.text(); }) .catch((error) => { // ignore errors here as they are handled in the components if (error === 400) throw error; if (error === 401) { handleLogout({ setUserSession: setUserSessionToLocalStorage, }); return; } // show error notification for all other errors if (notificationApi !== null && t !== null) { if (error === 500) { notificationApi["error"]({ message: t("common.request.failed.title"), description: t("common.request.failed.description"), }); } else { // other errors notificationApi["error"]({ message: t("common.request.failedInternetProblem.title"), description: t("common.request.failedInternetProblem.description"), }); } } throw error; }); } export function isDevelopmentEnv() { return process.env.NODE_ENV === "development"; } export function showInputsInvalidNotification(notificationApi, t) { notificationApi["warning"]({ message: t("common.request.inputsInvalid.title"), description: t("common.request.inputsInvalid.description"), }); } export function showPasswordIncorrectNotification(notificationApi, t) { notificationApi["warning"]({ message: t("common.request.passwordIncorrect.title"), description: t("common.request.passwordIncorrect.description"), }); } export function showUnkownErrorNotification(notificationApi, t) { notificationApi["error"]({ message: t("common.request.unknownError.title"), description: t("common.request.unknownError.description"), }); } export function handleLogout({ setUserSession }) { console.log("handleLogout"); if (setUserSession !== undefined) setUserSession(); window.location.href = Constants.ROUTE_PATHS.AUTHENTICATION.LOGIN; } export function FormatDatetime(datetime) { if (datetime === undefined || datetime === "0001-01-01T00:00:00Z") { return Constants.TEXT_EMPTY_PLACEHOLDER; } return new Date(datetime).toLocaleString("de-DE"); }