import {distinctUntilChanged, startWith, map, tap, share} from "rxjs/operators";
import { bind } from "@react-rxjs/core";
import { createSignal } from "@react-rxjs/utils";
import {combineLatest, ReplaySubject} from "rxjs";
import GENERAL_STORE_STATES from "@/shared/enum/general";
import getStore from "@/shared/store/index";
import GenericUserHelper from "@/shared/helper/user/generic";
const genericFormHelperInstances = {
meeting: new Map(),
task: new Map(),
persons: new Map(),
questionnaire: new Map(),
investigation: new Map(),
};
const formInfoDefault = {
status: GENERAL_STORE_STATES.INIT,
};
const createFormInfo = ({ status, signature, signedAt, deadline, category } = {}) => {
let issuedAt = "";
if (signature && status !== "EDIT") {
//https://stackoverflow.com/a/38552302
const base64 = signature.split(".")[1].replace(/-/g, "+").replace(/_/g, "/");
const jsonPayload = decodeURIComponent(
window
.atob(base64)
.split("")
.map((c) => "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2))
.join("")
);
issuedAt = JSON.parse(jsonPayload).iat * 1000;
}
const returnObject = { status: status ?? formInfoDefault.status, signedAt, issuedAt, category };
if (typeof deadline !== "undefined") {
returnObject.deadline = deadline;
}
return returnObject;
};
const GenericFormHelper = (type, id) => {
let storeId = id;
const storeType = type;
// TODO: Mobx seems like a better solution
let lastKnownFormInfo = formInfoDefault;
const { storeId$ } = getStore(storeType, storeId).getStore();
storeId$.subscribe((currentStoreId) => {
if (storeId !== currentStoreId) {
// Current workaround to add 'this' also as the other identifier.
const originalStore = genericFormHelperInstances[storeType].get(id);
if (originalStore) {
genericFormHelperInstances[storeType].set(currentStoreId, originalStore);
}
}
storeId = currentStoreId;
});
const [formInfoPipe$, updateFormInfo] = createSignal(createFormInfo);
formInfoPipe$.subscribe((newValue) => {
lastKnownFormInfo = newValue;
});
const generalFormInfo$ = formInfoPipe$.pipe(
startWith(null),
map((v) => v ?? lastKnownFormInfo),
distinctUntilChanged((prev, curr) => JSON.stringify(prev) === JSON.stringify(curr)),
share({
connector: () => new ReplaySubject(1),
resetOnRefCountZero: false, // Do not reset if ref count becomes zero
})
);
const isSubmitted$ = generalFormInfo$.pipe(
// In the future add more constraints here.
map(({ status }) => {
if (storeType === "meeting") {
return [GENERAL_STORE_STATES.SUBMITTED, "ASUB"].includes(status);
}
return status === GENERAL_STORE_STATES.SUBMITTED;
}),
distinctUntilChanged(),
);
const isFormReadOnly$ = combineLatest(
isSubmitted$,
GenericUserHelper.isMunicipalityStaff$
).pipe(
// Staff is not allowed to write changes to the questionnaire
map(([formReadyOnly, isStaff]) => formReadyOnly || (isStaff && type === "questionnaire"))
);
return {
get info$() {
return generalFormInfo$;
},
/**
*
* @param rawDynamoDBObject
* @param {boolean} [awaitResult=false] If true, wait for the result to return
* @returns {Promise<Object>|void}
*/
updateInfo: async function (rawDynamoDBObject, awaitResult = false) {
const fn = () => {
updateFormInfo({
...lastKnownFormInfo,
...rawDynamoDBObject
});
}
if (awaitResult) {
let subscription;
return new Promise((resolve) => {
subscription = formInfoPipe$.subscribe((value) => {
resolve(value);
});
fn();
}).then((v) => {
subscription.unsubscribe();
return v;
})
}
return void fn();
},
get isFormReadOnly$() {
return isFormReadOnly$;
},
get isSubmitted$() {
return isSubmitted$;
}
};
};
function getGenericFormHelper(type, id) {
// Presumably change Store to Factory design pattern
let store = genericFormHelperInstances[type].get(id);
if (!store) {
store = GenericFormHelper(type, id);
genericFormHelperInstances[type].set(id, store);
}
return store;
}
export const useGenericFormInfo = bind((type, id) => getGenericFormHelper(type, id).info$, formInfoDefault)[0];
export const useIsSubmitted = bind(
(type, id) => getGenericFormHelper(type, id).isSubmitted$,
null
)[0];
export const useIsFormReadOnly = bind((type, id) => getGenericFormHelper(type, id).isFormReadOnly$, false)[0];
export default getGenericFormHelper;