@fctc/interface-logic 4.2.7 → 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.mjs CHANGED
@@ -1606,9 +1606,9 @@ function applyBinaryOp(ast, context) {
1606
1606
  var DICT = {
1607
1607
  get(...args) {
1608
1608
  const { key, defValue } = parseArgs(args, ["key", "defValue"]);
1609
- const self = this;
1610
- if (key in self) {
1611
- return self[key];
1609
+ const self2 = this;
1610
+ if (key in self2) {
1611
+ return self2[key];
1612
1612
  } else if (defValue !== void 0) {
1613
1613
  return defValue;
1614
1614
  }
@@ -2229,7 +2229,8 @@ var initialState2 = {
2229
2229
  allowed_company_ids: [],
2230
2230
  lang: "vi_VN",
2231
2231
  tz: "Asia/Saigon"
2232
- }
2232
+ },
2233
+ isLocalMode: false
2233
2234
  };
2234
2235
  var envSlice = createSlice2({
2235
2236
  name: "env",
@@ -3859,7 +3860,220 @@ var handleClosingSessionService = (env) => {
3859
3860
 
3860
3861
  // src/services/pos-service/load-data-pos-session.ts
3861
3862
  import { useCallback as useCallback23 } from "react";
3863
+
3864
+ // src/services/filesystem-service/file-service.ts
3865
+ import { Directory, Encoding, Filesystem } from "@capacitor/filesystem";
3866
+ var fileService = {
3867
+ async read(path) {
3868
+ try {
3869
+ const res = await Filesystem.readFile({
3870
+ path,
3871
+ directory: Directory.Data,
3872
+ encoding: Encoding.UTF8
3873
+ });
3874
+ if (typeof res.data === "string") return res.data;
3875
+ if (res.data instanceof Blob) return await res.data.text();
3876
+ return null;
3877
+ } catch {
3878
+ return null;
3879
+ }
3880
+ },
3881
+ async write(path, data) {
3882
+ await Filesystem.writeFile({
3883
+ path,
3884
+ data,
3885
+ directory: Directory.Data,
3886
+ encoding: Encoding.UTF8,
3887
+ recursive: true
3888
+ });
3889
+ },
3890
+ async writeAtomic(path, data) {
3891
+ const tempPath = path + ".tmp";
3892
+ await Filesystem.writeFile({
3893
+ path: tempPath,
3894
+ data,
3895
+ directory: Directory.Data,
3896
+ encoding: Encoding.UTF8,
3897
+ recursive: true
3898
+ });
3899
+ try {
3900
+ await Filesystem.deleteFile({
3901
+ path,
3902
+ directory: Directory.Data
3903
+ });
3904
+ } catch {
3905
+ }
3906
+ await Filesystem.rename({
3907
+ from: tempPath,
3908
+ to: path,
3909
+ directory: Directory.Data
3910
+ });
3911
+ },
3912
+ async delete(path) {
3913
+ try {
3914
+ await Filesystem.deleteFile({
3915
+ path,
3916
+ directory: Directory.Data
3917
+ });
3918
+ } catch {
3919
+ }
3920
+ },
3921
+ async exists(path) {
3922
+ try {
3923
+ await Filesystem.stat({
3924
+ path,
3925
+ directory: Directory.Data
3926
+ });
3927
+ return true;
3928
+ } catch {
3929
+ return false;
3930
+ }
3931
+ },
3932
+ async mkdir(path) {
3933
+ try {
3934
+ await Filesystem.mkdir({
3935
+ path,
3936
+ directory: Directory.Data,
3937
+ recursive: true
3938
+ });
3939
+ } catch (e) {
3940
+ if (!String(e?.message).includes("Exists")) {
3941
+ throw e;
3942
+ }
3943
+ }
3944
+ },
3945
+ async list(path) {
3946
+ return Filesystem.readdir({
3947
+ path,
3948
+ directory: Directory.Data
3949
+ });
3950
+ },
3951
+ async getUri(path) {
3952
+ return Filesystem.getUri({
3953
+ path,
3954
+ directory: Directory.Data
3955
+ });
3956
+ }
3957
+ };
3958
+
3959
+ // src/services/filesystem-service/json-worker.ts
3960
+ self.addEventListener("message", async (ev) => {
3961
+ const { id, cmd, payload } = ev.data;
3962
+ try {
3963
+ if (cmd === "parse") {
3964
+ const parsed = JSON.parse(payload);
3965
+ self.postMessage({ id, ok: true, result: parsed });
3966
+ } else if (cmd === "stringify") {
3967
+ const str = JSON.stringify(payload);
3968
+ self.postMessage({ id, ok: true, result: str });
3969
+ }
3970
+ } catch (err) {
3971
+ self.postMessage({ id, ok: false, error: err?.message || String(err) });
3972
+ }
3973
+ });
3974
+ function spawnParseWorker(raw) {
3975
+ return new Promise((resolve, reject) => {
3976
+ const worker = new Worker(new URL("./json-worker.ts", import.meta.url), {
3977
+ type: "module"
3978
+ });
3979
+ const id = Math.random().toString(36).slice(2);
3980
+ worker.onmessage = (ev) => {
3981
+ const { ok, result, error } = ev.data;
3982
+ if (ok) {
3983
+ resolve(result);
3984
+ } else {
3985
+ reject(new Error(error));
3986
+ }
3987
+ worker.terminate();
3988
+ };
3989
+ worker.postMessage({ id, cmd: "parse", payload: raw });
3990
+ });
3991
+ }
3992
+ function spawnStringifyWorker(obj) {
3993
+ return new Promise((resolve, reject) => {
3994
+ const worker = new Worker(new URL("./json-worker.ts", import.meta.url), {
3995
+ type: "module"
3996
+ });
3997
+ worker.onmessage = (ev) => {
3998
+ const { ok, result, error } = ev.data;
3999
+ if (ok) resolve(result);
4000
+ else reject(new Error(error));
4001
+ worker.terminate();
4002
+ };
4003
+ worker.postMessage({ cmd: "stringify", payload: obj });
4004
+ });
4005
+ }
4006
+
4007
+ // src/services/filesystem-service/memory-cache.ts
4008
+ var MemoryCache = class {
4009
+ map = /* @__PURE__ */ new Map();
4010
+ get(k) {
4011
+ const e = this.map.get(k);
4012
+ if (!e) return null;
4013
+ if (e.ttl && Date.now() - e.t > e.ttl) {
4014
+ this.map.delete(k);
4015
+ return null;
4016
+ }
4017
+ return e.value;
4018
+ }
4019
+ set(k, v, ttl = 5 * 60 * 1e3) {
4020
+ this.map.set(k, { value: v, t: Date.now(), ttl });
4021
+ }
4022
+ del(k) {
4023
+ this.map.delete(k);
4024
+ }
4025
+ clear() {
4026
+ this.map.clear();
4027
+ }
4028
+ };
4029
+ var memoryCache = new MemoryCache();
4030
+
4031
+ // src/services/filesystem-service/model-loader.ts
4032
+ var MODELS_DIR = "pos/models";
4033
+ var MODELS_META_DIR = "pos/models_meta";
4034
+ async function loadData(includeMeta = true) {
4035
+ const listResult = await fileService.list(MODELS_DIR);
4036
+ if (!listResult || !Array.isArray(listResult.files)) {
4037
+ return {};
4038
+ }
4039
+ const result = {};
4040
+ for (const file of listResult.files) {
4041
+ if (file.type !== "file") continue;
4042
+ if (!file.name.endsWith(".json")) continue;
4043
+ const fileName = file.name;
4044
+ const modelName = fileName.replace(/\.json$/, "");
4045
+ const dataPath = `${MODELS_DIR}/${fileName}`;
4046
+ const metaPath = `${MODELS_META_DIR}/${encodeURIComponent(
4047
+ modelName
4048
+ )}.meta.json`;
4049
+ const rawData = await fileService.read(dataPath);
4050
+ if (!rawData) continue;
4051
+ const parsedData = await spawnParseWorker(rawData);
4052
+ const data = Array.isArray(parsedData) ? parsedData : [];
4053
+ if (!includeMeta) {
4054
+ result[modelName] = { data };
4055
+ continue;
4056
+ }
4057
+ const rawMeta = await fileService.read(metaPath);
4058
+ let fields = [];
4059
+ let relations = {};
4060
+ if (rawMeta) {
4061
+ const parsedMeta = await spawnParseWorker(rawMeta);
4062
+ fields = parsedMeta?.fields ?? [];
4063
+ relations = parsedMeta?.relations ?? {};
4064
+ }
4065
+ result[modelName] = {
4066
+ data,
4067
+ fields,
4068
+ relations
4069
+ };
4070
+ }
4071
+ return result;
4072
+ }
4073
+
4074
+ // src/services/pos-service/load-data-pos-session.ts
3862
4075
  var loadDataPosSessionService = (env) => {
4076
+ const isLocalMode = env?.isLocalMode;
3863
4077
  const loadDataPosSession = useCallback23(
3864
4078
  ({
3865
4079
  model,
@@ -3870,6 +4084,9 @@ var loadDataPosSessionService = (env) => {
3870
4084
  modelsToLoad = [],
3871
4085
  searchParams
3872
4086
  }) => {
4087
+ if (isLocalMode) {
4088
+ return loadData();
4089
+ }
3873
4090
  const jsonData = {
3874
4091
  model,
3875
4092
  method: "load_data" /* LOAD_DATA */,
@@ -3896,7 +4113,7 @@ var loadDataPosSessionService = (env) => {
3896
4113
  service
3897
4114
  );
3898
4115
  },
3899
- [env]
4116
+ [env, isLocalMode]
3900
4117
  );
3901
4118
  return {
3902
4119
  loadDataPosSession
@@ -4313,6 +4530,9 @@ import { useMutation as useMutation84 } from "@tanstack/react-query";
4313
4530
  // src/hooks/pos/use-update-order-status.ts
4314
4531
  import { useMutation as useMutation85 } from "@tanstack/react-query";
4315
4532
 
4533
+ // src/hooks/pos/use-init-snapshot.ts
4534
+ import { useMutation as useMutation86 } from "@tanstack/react-query";
4535
+
4316
4536
  // src/provider/service-provider.tsx
4317
4537
  import { jsx as jsx6 } from "react/jsx-runtime";
4318
4538
  var ServiceContext = createContext2(null);
@@ -6475,12 +6695,152 @@ function useDashboardService() {
6475
6695
  );
6476
6696
  return { readGroup, getDataChart };
6477
6697
  }
6698
+
6699
+ // src/services/filesystem-service/manifest.ts
6700
+ var MANIFEST_PATH = "pos/manifest.json";
6701
+ var MANIFEST_BAK_PATH = "pos/manifest.bak.json";
6702
+ async function writeManifest(manifest) {
6703
+ const oldRaw = await fileService.read(MANIFEST_PATH);
6704
+ if (oldRaw !== null) {
6705
+ await fileService.writeAtomic(MANIFEST_BAK_PATH, oldRaw);
6706
+ }
6707
+ await fileService.writeAtomic(MANIFEST_PATH, JSON.stringify(manifest));
6708
+ try {
6709
+ await fileService.delete(MANIFEST_BAK_PATH);
6710
+ } catch {
6711
+ }
6712
+ }
6713
+
6714
+ // src/services/filesystem-service/import-snapshot.ts
6715
+ var DATA_DIR = "pos";
6716
+ var MODELS_DIR2 = `${DATA_DIR}/models`;
6717
+ var MODELS_META_DIR2 = `${DATA_DIR}/models_meta`;
6718
+ var importSnapshot = async ({ data, onProgress }) => {
6719
+ onProgress?.(1, "Parsing snapshot");
6720
+ const parsed = await spawnParseWorker(data);
6721
+ const modelNames = Object.keys(parsed);
6722
+ const total = modelNames.length;
6723
+ const manifest = { version: (/* @__PURE__ */ new Date()).toISOString(), models: {} };
6724
+ const TMP_PREFIX = `pos/data/tmp_import_${Date.now()}`;
6725
+ await fileService.writeAtomic(`${TMP_PREFIX}/.marker`, "1");
6726
+ let i = 0;
6727
+ for (const model of modelNames) {
6728
+ i++;
6729
+ onProgress?.(
6730
+ Math.round(i / total * 100),
6731
+ `Processing ${model} (${i}/${total})`
6732
+ );
6733
+ const block = parsed[model];
6734
+ const dataPart = block?.data ?? block ?? [];
6735
+ const fields = block?.fields ?? [];
6736
+ const relations = block?.relations ?? {};
6737
+ const serialized = await spawnStringifyWorker(dataPart);
6738
+ const tmpModelPath = `${TMP_PREFIX}/${encodeURIComponent(model)}.json`;
6739
+ await fileService.writeAtomic(tmpModelPath, serialized);
6740
+ const meta = {
6741
+ fields,
6742
+ relations,
6743
+ count: Array.isArray(dataPart) ? dataPart.length : 0,
6744
+ writtenAt: (/* @__PURE__ */ new Date()).toISOString()
6745
+ };
6746
+ const tmpMetaPath = `${TMP_PREFIX}/${encodeURIComponent(model)}.meta.json`;
6747
+ await fileService.writeAtomic(tmpMetaPath, JSON.stringify(meta));
6748
+ manifest.models[model] = {
6749
+ file: `${MODELS_DIR2}/${encodeURIComponent(model)}.json`,
6750
+ metaFile: `${MODELS_META_DIR2}/${encodeURIComponent(model)}.meta.json`,
6751
+ count: meta.count,
6752
+ updatedAt: meta.writtenAt
6753
+ };
6754
+ }
6755
+ onProgress?.(95, "Committing import (moving files)");
6756
+ for (const model of modelNames) {
6757
+ const tmpModelPath = `${TMP_PREFIX}/${encodeURIComponent(model)}.json`;
6758
+ const finalModelPath = `${MODELS_DIR2}/${encodeURIComponent(model)}.json`;
6759
+ const tmpMetaPath = `${TMP_PREFIX}/${encodeURIComponent(model)}.meta.json`;
6760
+ const finalMetaPath = `${MODELS_META_DIR2}/${encodeURIComponent(
6761
+ model
6762
+ )}.meta.json`;
6763
+ const tmpRaw = await fileService.read(tmpModelPath);
6764
+ if (tmpRaw !== null) await fileService.writeAtomic(finalModelPath, tmpRaw);
6765
+ const tmpMetaRaw = await fileService.read(tmpMetaPath);
6766
+ if (tmpMetaRaw !== null)
6767
+ await fileService.writeAtomic(finalMetaPath, tmpMetaRaw);
6768
+ onProgress?.(
6769
+ 95 + Math.round(
6770
+ (Object.keys(manifest.models).indexOf(model) + 1) / modelNames.length * 5
6771
+ ),
6772
+ `Committed ${model}`
6773
+ );
6774
+ }
6775
+ await writeManifest(manifest);
6776
+ try {
6777
+ for (const model of modelNames) {
6778
+ await fileService.delete(
6779
+ `${TMP_PREFIX}/${encodeURIComponent(model)}.json`
6780
+ );
6781
+ await fileService.delete(
6782
+ `${TMP_PREFIX}/${encodeURIComponent(model)}.meta.json`
6783
+ );
6784
+ }
6785
+ await fileService.delete(`${TMP_PREFIX}/.marker`);
6786
+ } catch (e) {
6787
+ console.log("Failed to cleanup tmp import files:", e);
6788
+ }
6789
+ onProgress?.(100, "Import complete");
6790
+ return manifest;
6791
+ };
6792
+ var import_snapshot_default = importSnapshot;
6793
+
6794
+ // src/services/filesystem-service/init-snapshot.ts
6795
+ var isSnapshotReady = async () => {
6796
+ try {
6797
+ const raw = await fileService.read("pos/manifest.json");
6798
+ if (!raw) return false;
6799
+ const manifest = JSON.parse(raw);
6800
+ if (!manifest.models || typeof manifest.models !== "object") {
6801
+ return false;
6802
+ }
6803
+ const modelEntries = Object.values(manifest.models);
6804
+ if (modelEntries.length === 0) return false;
6805
+ const firstModel = modelEntries[0];
6806
+ if (!firstModel.file) return false;
6807
+ const modelExists = await fileService.exists(firstModel.file);
6808
+ return modelExists;
6809
+ } catch {
6810
+ return false;
6811
+ }
6812
+ };
6813
+ async function initSnapshot(onProgress) {
6814
+ const ready = await isSnapshotReady();
6815
+ if (ready) {
6816
+ console.log("skip initialization.");
6817
+ return;
6818
+ }
6819
+ console.log("initializing from data.json...");
6820
+ const jsonData = await fetch("/data.json").then((r) => r.text());
6821
+ if (!jsonData) {
6822
+ console.error("cannot load data.json");
6823
+ return;
6824
+ }
6825
+ await import_snapshot_default({
6826
+ data: jsonData,
6827
+ onProgress
6828
+ });
6829
+ }
6830
+
6831
+ // src/services/filesystem-service/index.ts
6832
+ var useFileSystemService = () => {
6833
+ return {
6834
+ initSnapshot
6835
+ };
6836
+ };
6478
6837
  export {
6479
6838
  useActionService,
6480
6839
  useAuthService,
6481
6840
  useCompanyService,
6482
6841
  useDashboardService,
6483
6842
  useExcelService,
6843
+ useFileSystemService,
6484
6844
  useFormService,
6485
6845
  useKanbanService,
6486
6846
  useModelService,
package/dist/store.js CHANGED
@@ -146,7 +146,8 @@ var initialState2 = {
146
146
  allowed_company_ids: [],
147
147
  lang: "vi_VN",
148
148
  tz: "Asia/Saigon"
149
- }
149
+ },
150
+ isLocalMode: false
150
151
  };
151
152
  var envSlice = (0, import_toolkit2.createSlice)({
152
153
  name: "env",
package/dist/store.mjs CHANGED
@@ -41,7 +41,8 @@ var initialState2 = {
41
41
  allowed_company_ids: [],
42
42
  lang: "vi_VN",
43
43
  tz: "Asia/Saigon"
44
- }
44
+ },
45
+ isLocalMode: false
45
46
  };
46
47
  var envSlice = createSlice2({
47
48
  name: "env",
package/package.json CHANGED
@@ -1,90 +1,91 @@
1
- {
2
- "name": "@fctc/interface-logic",
3
- "version": "4.2.7",
4
- "types": "dist/index.d.ts",
5
- "main": "dist/index.cjs",
6
- "module": "dist/index.mjs",
7
- "exports": {
8
- ".": {
9
- "types": "./dist/index.d.ts",
10
- "import": "./dist/index.mjs",
11
- "require": "./dist/index.cjs"
12
- },
13
- "./configs": {
14
- "types": "./dist/configs.d.ts",
15
- "import": "./dist/configs.mjs",
16
- "require": "./dist/configs.cjs"
17
- },
18
- "./constants": {
19
- "types": "./dist/constants.d.ts",
20
- "import": "./dist/constants.mjs",
21
- "require": "./dist/constants.cjs"
22
- },
23
- "./environment": {
24
- "types": "./dist/environment.d.ts",
25
- "import": "./dist/environment.mjs",
26
- "require": "./dist/environment.cjs"
27
- },
28
- "./hooks": {
29
- "types": "./dist/hooks.d.ts",
30
- "import": "./dist/hooks.mjs",
31
- "require": "./dist/hooks.cjs"
32
- },
33
- "./provider": {
34
- "types": "./dist/provider.d.ts",
35
- "import": "./dist/provider.mjs",
36
- "require": "./dist/provider.cjs"
37
- },
38
- "./services": {
39
- "types": "./dist/services.d.ts",
40
- "import": "./dist/services.mjs",
41
- "require": "./dist/services.cjs"
42
- },
43
- "./store": {
44
- "types": "./dist/store.d.ts",
45
- "import": "./dist/store.mjs",
46
- "require": "./dist/store.cjs"
47
- },
48
- "./utils": {
49
- "types": "./dist/utils.d.ts",
50
- "import": "./dist/utils.mjs",
51
- "require": "./dist/utils.cjs"
52
- },
53
- "./types": {
54
- "types": "./dist/types.d.ts",
55
- "import": "./dist/types.mjs",
56
- "require": "./dist/types.cjs"
57
- },
58
- "./models": {
59
- "types": "./dist/models.d.ts",
60
- "import": "./dist/models.mjs",
61
- "require": "./dist/models.cjs"
62
- }
63
- },
64
- "files": [
65
- "dist"
66
- ],
67
- "scripts": {
68
- "build": "tsup",
69
- "test": "jest"
70
- },
71
- "peerDependencies": {
72
- "react": "18.0.0",
73
- "@tanstack/react-query": "^5.83.0"
74
- },
75
- "dependencies": {
76
- "@reduxjs/toolkit": "^2.8.2",
77
- "@tanstack/react-query": "^5.83.0",
78
- "axios": "^1.11.0",
79
- "moment": "^2.30.1",
80
- "react-redux": "^9.2.0"
81
- },
82
- "devDependencies": {
83
- "@types/react": "^18.3.1",
84
- "react": "18.0.0",
85
- "jest": "^29.7.0",
86
- "tsup": "^8.0.0",
87
- "typescript": "^5.8.2"
88
- },
89
- "packageManager": "yarn@1.22.0"
90
- }
1
+ {
2
+ "name": "@fctc/interface-logic",
3
+ "version": "4.2.8",
4
+ "types": "dist/index.d.ts",
5
+ "main": "dist/index.cjs",
6
+ "module": "dist/index.mjs",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "import": "./dist/index.mjs",
11
+ "require": "./dist/index.cjs"
12
+ },
13
+ "./configs": {
14
+ "types": "./dist/configs.d.ts",
15
+ "import": "./dist/configs.mjs",
16
+ "require": "./dist/configs.cjs"
17
+ },
18
+ "./constants": {
19
+ "types": "./dist/constants.d.ts",
20
+ "import": "./dist/constants.mjs",
21
+ "require": "./dist/constants.cjs"
22
+ },
23
+ "./environment": {
24
+ "types": "./dist/environment.d.ts",
25
+ "import": "./dist/environment.mjs",
26
+ "require": "./dist/environment.cjs"
27
+ },
28
+ "./hooks": {
29
+ "types": "./dist/hooks.d.ts",
30
+ "import": "./dist/hooks.mjs",
31
+ "require": "./dist/hooks.cjs"
32
+ },
33
+ "./provider": {
34
+ "types": "./dist/provider.d.ts",
35
+ "import": "./dist/provider.mjs",
36
+ "require": "./dist/provider.cjs"
37
+ },
38
+ "./services": {
39
+ "types": "./dist/services.d.ts",
40
+ "import": "./dist/services.mjs",
41
+ "require": "./dist/services.cjs"
42
+ },
43
+ "./store": {
44
+ "types": "./dist/store.d.ts",
45
+ "import": "./dist/store.mjs",
46
+ "require": "./dist/store.cjs"
47
+ },
48
+ "./utils": {
49
+ "types": "./dist/utils.d.ts",
50
+ "import": "./dist/utils.mjs",
51
+ "require": "./dist/utils.cjs"
52
+ },
53
+ "./types": {
54
+ "types": "./dist/types.d.ts",
55
+ "import": "./dist/types.mjs",
56
+ "require": "./dist/types.cjs"
57
+ },
58
+ "./models": {
59
+ "types": "./dist/models.d.ts",
60
+ "import": "./dist/models.mjs",
61
+ "require": "./dist/models.cjs"
62
+ }
63
+ },
64
+ "files": [
65
+ "dist"
66
+ ],
67
+ "scripts": {
68
+ "build": "tsup",
69
+ "test": "jest"
70
+ },
71
+ "peerDependencies": {
72
+ "@tanstack/react-query": "^5.83.0",
73
+ "react": "18.0.0"
74
+ },
75
+ "dependencies": {
76
+ "@capacitor/filesystem": "^8.0.0",
77
+ "@reduxjs/toolkit": "^2.8.2",
78
+ "@tanstack/react-query": "^5.83.0",
79
+ "axios": "^1.11.0",
80
+ "moment": "^2.30.1",
81
+ "react-redux": "^9.2.0"
82
+ },
83
+ "devDependencies": {
84
+ "@types/react": "^18.3.1",
85
+ "jest": "^29.7.0",
86
+ "react": "18.0.0",
87
+ "tsup": "^8.0.0",
88
+ "typescript": "^5.8.2"
89
+ },
90
+ "packageManager": "yarn@1.22.0"
91
+ }