@fctc/interface-logic 4.2.6 → 4.2.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/services.js CHANGED
@@ -35,6 +35,7 @@ __export(services_exports, {
35
35
  useCompanyService: () => useCompanyService,
36
36
  useDashboardService: () => useDashboardService,
37
37
  useExcelService: () => useExcelService,
38
+ useFileSystemService: () => useFileSystemService,
38
39
  useFormService: () => useFormService,
39
40
  useKanbanService: () => useKanbanService,
40
41
  useModelService: () => useModelService,
@@ -1652,9 +1653,9 @@ function applyBinaryOp(ast, context) {
1652
1653
  var DICT = {
1653
1654
  get(...args) {
1654
1655
  const { key, defValue } = parseArgs(args, ["key", "defValue"]);
1655
- const self = this;
1656
- if (key in self) {
1657
- return self[key];
1656
+ const self2 = this;
1657
+ if (key in self2) {
1658
+ return self2[key];
1658
1659
  } else if (defValue !== void 0) {
1659
1660
  return defValue;
1660
1661
  }
@@ -2275,7 +2276,8 @@ var initialState2 = {
2275
2276
  allowed_company_ids: [],
2276
2277
  lang: "vi_VN",
2277
2278
  tz: "Asia/Saigon"
2278
- }
2279
+ },
2280
+ isLocalMode: false
2279
2281
  };
2280
2282
  var envSlice = (0, import_toolkit2.createSlice)({
2281
2283
  name: "env",
@@ -3905,7 +3907,221 @@ var handleClosingSessionService = (env) => {
3905
3907
 
3906
3908
  // src/services/pos-service/load-data-pos-session.ts
3907
3909
  var import_react26 = require("react");
3910
+
3911
+ // src/services/filesystem-service/file-service.ts
3912
+ var import_filesystem = require("@capacitor/filesystem");
3913
+ var fileService = {
3914
+ async read(path) {
3915
+ try {
3916
+ const res = await import_filesystem.Filesystem.readFile({
3917
+ path,
3918
+ directory: import_filesystem.Directory.Data,
3919
+ encoding: import_filesystem.Encoding.UTF8
3920
+ });
3921
+ if (typeof res.data === "string") return res.data;
3922
+ if (res.data instanceof Blob) return await res.data.text();
3923
+ return null;
3924
+ } catch {
3925
+ return null;
3926
+ }
3927
+ },
3928
+ async write(path, data) {
3929
+ await import_filesystem.Filesystem.writeFile({
3930
+ path,
3931
+ data,
3932
+ directory: import_filesystem.Directory.Data,
3933
+ encoding: import_filesystem.Encoding.UTF8,
3934
+ recursive: true
3935
+ });
3936
+ },
3937
+ async writeAtomic(path, data) {
3938
+ const tempPath = path + ".tmp";
3939
+ await import_filesystem.Filesystem.writeFile({
3940
+ path: tempPath,
3941
+ data,
3942
+ directory: import_filesystem.Directory.Data,
3943
+ encoding: import_filesystem.Encoding.UTF8,
3944
+ recursive: true
3945
+ });
3946
+ try {
3947
+ await import_filesystem.Filesystem.deleteFile({
3948
+ path,
3949
+ directory: import_filesystem.Directory.Data
3950
+ });
3951
+ } catch {
3952
+ }
3953
+ await import_filesystem.Filesystem.rename({
3954
+ from: tempPath,
3955
+ to: path,
3956
+ directory: import_filesystem.Directory.Data
3957
+ });
3958
+ },
3959
+ async delete(path) {
3960
+ try {
3961
+ await import_filesystem.Filesystem.deleteFile({
3962
+ path,
3963
+ directory: import_filesystem.Directory.Data
3964
+ });
3965
+ } catch {
3966
+ }
3967
+ },
3968
+ async exists(path) {
3969
+ try {
3970
+ await import_filesystem.Filesystem.stat({
3971
+ path,
3972
+ directory: import_filesystem.Directory.Data
3973
+ });
3974
+ return true;
3975
+ } catch {
3976
+ return false;
3977
+ }
3978
+ },
3979
+ async mkdir(path) {
3980
+ try {
3981
+ await import_filesystem.Filesystem.mkdir({
3982
+ path,
3983
+ directory: import_filesystem.Directory.Data,
3984
+ recursive: true
3985
+ });
3986
+ } catch (e) {
3987
+ if (!String(e?.message).includes("Exists")) {
3988
+ throw e;
3989
+ }
3990
+ }
3991
+ },
3992
+ async list(path) {
3993
+ return import_filesystem.Filesystem.readdir({
3994
+ path,
3995
+ directory: import_filesystem.Directory.Data
3996
+ });
3997
+ },
3998
+ async getUri(path) {
3999
+ return import_filesystem.Filesystem.getUri({
4000
+ path,
4001
+ directory: import_filesystem.Directory.Data
4002
+ });
4003
+ }
4004
+ };
4005
+
4006
+ // src/services/filesystem-service/json-worker.ts
4007
+ var import_meta = {};
4008
+ self.addEventListener("message", async (ev) => {
4009
+ const { id, cmd, payload } = ev.data;
4010
+ try {
4011
+ if (cmd === "parse") {
4012
+ const parsed = JSON.parse(payload);
4013
+ self.postMessage({ id, ok: true, result: parsed });
4014
+ } else if (cmd === "stringify") {
4015
+ const str = JSON.stringify(payload);
4016
+ self.postMessage({ id, ok: true, result: str });
4017
+ }
4018
+ } catch (err) {
4019
+ self.postMessage({ id, ok: false, error: err?.message || String(err) });
4020
+ }
4021
+ });
4022
+ function spawnParseWorker(raw) {
4023
+ return new Promise((resolve, reject) => {
4024
+ const worker = new Worker(new URL("./json-worker.ts", import_meta.url), {
4025
+ type: "module"
4026
+ });
4027
+ const id = Math.random().toString(36).slice(2);
4028
+ worker.onmessage = (ev) => {
4029
+ const { ok, result, error } = ev.data;
4030
+ if (ok) {
4031
+ resolve(result);
4032
+ } else {
4033
+ reject(new Error(error));
4034
+ }
4035
+ worker.terminate();
4036
+ };
4037
+ worker.postMessage({ id, cmd: "parse", payload: raw });
4038
+ });
4039
+ }
4040
+ function spawnStringifyWorker(obj) {
4041
+ return new Promise((resolve, reject) => {
4042
+ const worker = new Worker(new URL("./json-worker.ts", import_meta.url), {
4043
+ type: "module"
4044
+ });
4045
+ worker.onmessage = (ev) => {
4046
+ const { ok, result, error } = ev.data;
4047
+ if (ok) resolve(result);
4048
+ else reject(new Error(error));
4049
+ worker.terminate();
4050
+ };
4051
+ worker.postMessage({ cmd: "stringify", payload: obj });
4052
+ });
4053
+ }
4054
+
4055
+ // src/services/filesystem-service/memory-cache.ts
4056
+ var MemoryCache = class {
4057
+ map = /* @__PURE__ */ new Map();
4058
+ get(k) {
4059
+ const e = this.map.get(k);
4060
+ if (!e) return null;
4061
+ if (e.ttl && Date.now() - e.t > e.ttl) {
4062
+ this.map.delete(k);
4063
+ return null;
4064
+ }
4065
+ return e.value;
4066
+ }
4067
+ set(k, v, ttl = 5 * 60 * 1e3) {
4068
+ this.map.set(k, { value: v, t: Date.now(), ttl });
4069
+ }
4070
+ del(k) {
4071
+ this.map.delete(k);
4072
+ }
4073
+ clear() {
4074
+ this.map.clear();
4075
+ }
4076
+ };
4077
+ var memoryCache = new MemoryCache();
4078
+
4079
+ // src/services/filesystem-service/model-loader.ts
4080
+ var MODELS_DIR = "pos/models";
4081
+ var MODELS_META_DIR = "pos/models_meta";
4082
+ async function loadData(includeMeta = true) {
4083
+ const listResult = await fileService.list(MODELS_DIR);
4084
+ if (!listResult || !Array.isArray(listResult.files)) {
4085
+ return {};
4086
+ }
4087
+ const result = {};
4088
+ for (const file of listResult.files) {
4089
+ if (file.type !== "file") continue;
4090
+ if (!file.name.endsWith(".json")) continue;
4091
+ const fileName = file.name;
4092
+ const modelName = fileName.replace(/\.json$/, "");
4093
+ const dataPath = `${MODELS_DIR}/${fileName}`;
4094
+ const metaPath = `${MODELS_META_DIR}/${encodeURIComponent(
4095
+ modelName
4096
+ )}.meta.json`;
4097
+ const rawData = await fileService.read(dataPath);
4098
+ if (!rawData) continue;
4099
+ const parsedData = await spawnParseWorker(rawData);
4100
+ const data = Array.isArray(parsedData) ? parsedData : [];
4101
+ if (!includeMeta) {
4102
+ result[modelName] = { data };
4103
+ continue;
4104
+ }
4105
+ const rawMeta = await fileService.read(metaPath);
4106
+ let fields = [];
4107
+ let relations = {};
4108
+ if (rawMeta) {
4109
+ const parsedMeta = await spawnParseWorker(rawMeta);
4110
+ fields = parsedMeta?.fields ?? [];
4111
+ relations = parsedMeta?.relations ?? {};
4112
+ }
4113
+ result[modelName] = {
4114
+ data,
4115
+ fields,
4116
+ relations
4117
+ };
4118
+ }
4119
+ return result;
4120
+ }
4121
+
4122
+ // src/services/pos-service/load-data-pos-session.ts
3908
4123
  var loadDataPosSessionService = (env) => {
4124
+ const isLocalMode = env?.isLocalMode;
3909
4125
  const loadDataPosSession = (0, import_react26.useCallback)(
3910
4126
  ({
3911
4127
  model,
@@ -3916,6 +4132,9 @@ var loadDataPosSessionService = (env) => {
3916
4132
  modelsToLoad = [],
3917
4133
  searchParams
3918
4134
  }) => {
4135
+ if (isLocalMode) {
4136
+ return loadData();
4137
+ }
3919
4138
  const jsonData = {
3920
4139
  model,
3921
4140
  method: "load_data" /* LOAD_DATA */,
@@ -3942,7 +4161,7 @@ var loadDataPosSessionService = (env) => {
3942
4161
  service
3943
4162
  );
3944
4163
  },
3945
- [env]
4164
+ [env, isLocalMode]
3946
4165
  );
3947
4166
  return {
3948
4167
  loadDataPosSession
@@ -4359,6 +4578,9 @@ var import_react_query111 = require("@tanstack/react-query");
4359
4578
  // src/hooks/pos/use-update-order-status.ts
4360
4579
  var import_react_query112 = require("@tanstack/react-query");
4361
4580
 
4581
+ // src/hooks/pos/use-init-snapshot.ts
4582
+ var import_react_query113 = require("@tanstack/react-query");
4583
+
4362
4584
  // src/provider/service-provider.tsx
4363
4585
  var import_jsx_runtime6 = require("react/jsx-runtime");
4364
4586
  var ServiceContext = (0, import_react35.createContext)(null);
@@ -6521,6 +6743,145 @@ function useDashboardService() {
6521
6743
  );
6522
6744
  return { readGroup, getDataChart };
6523
6745
  }
6746
+
6747
+ // src/services/filesystem-service/manifest.ts
6748
+ var MANIFEST_PATH = "pos/manifest.json";
6749
+ var MANIFEST_BAK_PATH = "pos/manifest.bak.json";
6750
+ async function writeManifest(manifest) {
6751
+ const oldRaw = await fileService.read(MANIFEST_PATH);
6752
+ if (oldRaw !== null) {
6753
+ await fileService.writeAtomic(MANIFEST_BAK_PATH, oldRaw);
6754
+ }
6755
+ await fileService.writeAtomic(MANIFEST_PATH, JSON.stringify(manifest));
6756
+ try {
6757
+ await fileService.delete(MANIFEST_BAK_PATH);
6758
+ } catch {
6759
+ }
6760
+ }
6761
+
6762
+ // src/services/filesystem-service/import-snapshot.ts
6763
+ var DATA_DIR = "pos";
6764
+ var MODELS_DIR2 = `${DATA_DIR}/models`;
6765
+ var MODELS_META_DIR2 = `${DATA_DIR}/models_meta`;
6766
+ var importSnapshot = async ({ data, onProgress }) => {
6767
+ onProgress?.(1, "Parsing snapshot");
6768
+ const parsed = await spawnParseWorker(data);
6769
+ const modelNames = Object.keys(parsed);
6770
+ const total = modelNames.length;
6771
+ const manifest = { version: (/* @__PURE__ */ new Date()).toISOString(), models: {} };
6772
+ const TMP_PREFIX = `pos/data/tmp_import_${Date.now()}`;
6773
+ await fileService.writeAtomic(`${TMP_PREFIX}/.marker`, "1");
6774
+ let i = 0;
6775
+ for (const model of modelNames) {
6776
+ i++;
6777
+ onProgress?.(
6778
+ Math.round(i / total * 100),
6779
+ `Processing ${model} (${i}/${total})`
6780
+ );
6781
+ const block = parsed[model];
6782
+ const dataPart = block?.data ?? block ?? [];
6783
+ const fields = block?.fields ?? [];
6784
+ const relations = block?.relations ?? {};
6785
+ const serialized = await spawnStringifyWorker(dataPart);
6786
+ const tmpModelPath = `${TMP_PREFIX}/${encodeURIComponent(model)}.json`;
6787
+ await fileService.writeAtomic(tmpModelPath, serialized);
6788
+ const meta = {
6789
+ fields,
6790
+ relations,
6791
+ count: Array.isArray(dataPart) ? dataPart.length : 0,
6792
+ writtenAt: (/* @__PURE__ */ new Date()).toISOString()
6793
+ };
6794
+ const tmpMetaPath = `${TMP_PREFIX}/${encodeURIComponent(model)}.meta.json`;
6795
+ await fileService.writeAtomic(tmpMetaPath, JSON.stringify(meta));
6796
+ manifest.models[model] = {
6797
+ file: `${MODELS_DIR2}/${encodeURIComponent(model)}.json`,
6798
+ metaFile: `${MODELS_META_DIR2}/${encodeURIComponent(model)}.meta.json`,
6799
+ count: meta.count,
6800
+ updatedAt: meta.writtenAt
6801
+ };
6802
+ }
6803
+ onProgress?.(95, "Committing import (moving files)");
6804
+ for (const model of modelNames) {
6805
+ const tmpModelPath = `${TMP_PREFIX}/${encodeURIComponent(model)}.json`;
6806
+ const finalModelPath = `${MODELS_DIR2}/${encodeURIComponent(model)}.json`;
6807
+ const tmpMetaPath = `${TMP_PREFIX}/${encodeURIComponent(model)}.meta.json`;
6808
+ const finalMetaPath = `${MODELS_META_DIR2}/${encodeURIComponent(
6809
+ model
6810
+ )}.meta.json`;
6811
+ const tmpRaw = await fileService.read(tmpModelPath);
6812
+ if (tmpRaw !== null) await fileService.writeAtomic(finalModelPath, tmpRaw);
6813
+ const tmpMetaRaw = await fileService.read(tmpMetaPath);
6814
+ if (tmpMetaRaw !== null)
6815
+ await fileService.writeAtomic(finalMetaPath, tmpMetaRaw);
6816
+ onProgress?.(
6817
+ 95 + Math.round(
6818
+ (Object.keys(manifest.models).indexOf(model) + 1) / modelNames.length * 5
6819
+ ),
6820
+ `Committed ${model}`
6821
+ );
6822
+ }
6823
+ await writeManifest(manifest);
6824
+ try {
6825
+ for (const model of modelNames) {
6826
+ await fileService.delete(
6827
+ `${TMP_PREFIX}/${encodeURIComponent(model)}.json`
6828
+ );
6829
+ await fileService.delete(
6830
+ `${TMP_PREFIX}/${encodeURIComponent(model)}.meta.json`
6831
+ );
6832
+ }
6833
+ await fileService.delete(`${TMP_PREFIX}/.marker`);
6834
+ } catch (e) {
6835
+ console.log("Failed to cleanup tmp import files:", e);
6836
+ }
6837
+ onProgress?.(100, "Import complete");
6838
+ return manifest;
6839
+ };
6840
+ var import_snapshot_default = importSnapshot;
6841
+
6842
+ // src/services/filesystem-service/init-snapshot.ts
6843
+ var isSnapshotReady = async () => {
6844
+ try {
6845
+ const raw = await fileService.read("pos/manifest.json");
6846
+ if (!raw) return false;
6847
+ const manifest = JSON.parse(raw);
6848
+ if (!manifest.models || typeof manifest.models !== "object") {
6849
+ return false;
6850
+ }
6851
+ const modelEntries = Object.values(manifest.models);
6852
+ if (modelEntries.length === 0) return false;
6853
+ const firstModel = modelEntries[0];
6854
+ if (!firstModel.file) return false;
6855
+ const modelExists = await fileService.exists(firstModel.file);
6856
+ return modelExists;
6857
+ } catch {
6858
+ return false;
6859
+ }
6860
+ };
6861
+ async function initSnapshot(onProgress) {
6862
+ const ready = await isSnapshotReady();
6863
+ if (ready) {
6864
+ console.log("skip initialization.");
6865
+ return;
6866
+ }
6867
+ console.log("initializing from data.json...");
6868
+ const jsonData = await fetch("/data.json").then((r) => r.text());
6869
+ if (!jsonData) {
6870
+ console.error("cannot load data.json");
6871
+ return;
6872
+ }
6873
+ await import_snapshot_default({
6874
+ data: jsonData,
6875
+ onProgress
6876
+ });
6877
+ }
6878
+
6879
+ // src/services/filesystem-service/index.ts
6880
+ var useFileSystemService = () => {
6881
+ return {
6882
+ initSnapshot
6883
+ };
6884
+ };
6524
6885
  // Annotate the CommonJS export names for ESM import in node:
6525
6886
  0 && (module.exports = {
6526
6887
  useActionService,
@@ -6528,6 +6889,7 @@ function useDashboardService() {
6528
6889
  useCompanyService,
6529
6890
  useDashboardService,
6530
6891
  useExcelService,
6892
+ useFileSystemService,
6531
6893
  useFormService,
6532
6894
  useKanbanService,
6533
6895
  useModelService,