diff --git a/client/App.tsx b/client/App.tsx
index 7613393e295e2de9235158b5d3984ddace839d01..eb83428ee07c2b3a88a0d054c55b4552a2d2e3a5 100644
--- a/client/App.tsx
+++ b/client/App.tsx
@@ -2,9 +2,11 @@ import { StripeProvider } from '@stripe/stripe-react-native';
import Constants from 'expo-constants';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
-import CheckoutScreen from './CheckoutScreen';
+import CheckoutScreen from './screens/CheckoutScreen';
import ScanScreen from './screens/ScanScreen';
import CartScreen from './screens/CartScreen';
+import PaymentHistoryScreen from './screens/HistoryPaymentsScreen';
+import { ThemeProvider } from './ThemeContext';
const Stack = createNativeStackNavigator();
const stripePK = Constants.manifest.extra.stripePK;
@@ -12,13 +14,14 @@ const stripePK = Constants.manifest.extra.stripePK;
export default function App() {
return (
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
);
}
diff --git a/client/database/db.js b/client/database/db.js
index 23a84ac2c330682252de9c21ab1a2397b0a7cb0f..693088e57a9e75e0bc3a61b2e626fab866f3503f 100644
--- a/client/database/db.js
+++ b/client/database/db.js
@@ -19,22 +19,9 @@ db.transaction((tx) => {
);
});
- const createHistoryTablePromise = new Promise((resolve, reject) => {
- tx.executeSql(
- 'CREATE TABLE IF NOT EXISTS history (id INTEGER PRIMARY KEY, name TEXT NOT NULL, price REAL NOT NULL, date TEXT NOT NULL)',
- [],
- () => {
- console.log('Table "history" created successfully');
- resolve();
- },
- (error) => {
- reject(error);
- }
- );
- });
- Promise.all([createItemsTablePromise, createHistoryTablePromise]).then(() => {
- console.log('Inside transaction, after creating both tables');
+ Promise.all([createItemsTablePromise]).then(() => {
+ console.log('Inside transaction, after creating tables');
});
});
diff --git a/client/database/dbUtils.js b/client/database/dbUtils.js
new file mode 100644
index 0000000000000000000000000000000000000000..73c434e77f523cd00912d823bbcb2e7ea2c988fb
--- /dev/null
+++ b/client/database/dbUtils.js
@@ -0,0 +1,126 @@
+import db from './db';
+
+export const getItemsWithQuantities = () => {
+ return new Promise((resolve, reject) => {
+ db.transaction((tx) => {
+ tx.executeSql('SELECT * FROM items', [], (_, { rows }) => {
+ const items = rows._array;
+ resolve(items);
+ });
+ });
+ });
+};
+
+export const deleteItem = (itemId) => {
+ return new Promise((resolve, reject) => {
+ db.transaction((tx) => {
+ tx.executeSql(
+ 'DELETE FROM items WHERE id = ?',
+ [itemId],
+ (_, result) => {
+ console.log(`Item with ID ${itemId} deleted successfully`);
+ resolve(result);
+ },
+ (error) => {
+ console.log(`Error deleting item with ID ${itemId}:`, error);
+ reject(error);
+ }
+ );
+ });
+ });
+};
+
+
+export const increaseQuantity = (itemId) => {
+ return new Promise((resolve, reject) => {
+ db.transaction((tx) => {
+ tx.executeSql(
+ 'UPDATE items SET quantity = quantity + 1 WHERE id = ?',
+ [itemId],
+ (_, result) => {
+ resolve(result);
+ },
+ (error) => {
+ reject(error);
+ }
+ );
+ });
+ });
+};
+
+
+export const checkIfLocalItemExists = (apiId) => {
+ return new Promise((resolve, reject) => {
+ db.transaction((tx) => {
+ tx.executeSql(
+ 'SELECT * FROM items WHERE id = ?',
+ [apiId],
+ (_, { rows: { _array } }) => {
+ if (_array.length > 0) {
+ resolve(_array[0]);
+ } else {
+ resolve(null);
+ }
+ },
+ (_, error) => {
+ reject(error);
+ }
+ );
+ });
+ });
+};
+
+export const updateLocalItemQuantity = (item_id, newQuantity) => {
+ return new Promise((resolve, reject) => {
+ db.transaction((tx) => {
+ tx.executeSql(
+ 'UPDATE items SET quantity = ? WHERE id = ?',
+ [newQuantity, item_id],
+ (_, results) => {
+ console.log(`Item with ID ${item_id} updated in the local db (quantity: ${newQuantity})`);
+ resolve(results);
+ },
+ (error) => {
+ console.log('Error updating item in the local database:', error);
+ reject(error);
+ }
+ );
+ });
+ });
+};
+
+export const decreaseQuantity = (itemId) => {
+ return new Promise((resolve, reject) => {
+ db.transaction((tx) => {
+ tx.executeSql(
+ 'UPDATE items SET quantity = CASE WHEN quantity > 1 THEN quantity - 1 ELSE 1 END WHERE id = ?',
+ [itemId],
+ (_, result) => {
+ resolve(result);
+ },
+ (error) => {
+ reject(error);
+ }
+ );
+ });
+ });
+};
+
+export const insertItem = (apiId, name, price) => {
+ return new Promise((resolve, reject) => {
+ db.transaction((tx) => {
+ tx.executeSql(
+ 'INSERT INTO items (id, name, price, quantity) VALUES (?, ?, ?, ?)',
+ [apiId, name, price, 1],
+ (_, results) => {
+ console.log(`Item ${name} added in local db (quantity: 1)`);
+ resolve(results);
+ },
+ (error) => {
+ console.log('Error adding item to local database:', error);
+ reject(error);
+ }
+ );
+ });
+ });
+};
diff --git a/client/package-lock.json b/client/package-lock.json
index 4cd4e69d0fe20153b0917ae6c1a25bf9fc57e14a..20784ab02d16c21416113ac51bbd6cd270a65446 100644
--- a/client/package-lock.json
+++ b/client/package-lock.json
@@ -8,10 +8,12 @@
"name": "client",
"version": "1.0.0",
"dependencies": {
+ "@react-native-async-storage/async-storage": "1.17.11",
"@react-navigation/native": "^6.1.9",
"@react-navigation/native-stack": "^6.9.16",
"@react-navigation/stack": "^6.3.20",
"@stripe/stripe-react-native": "0.23.3",
+ "date-fns": "^2.30.0",
"expo": "^48.0.0",
"expo-barcode-scanner": "~12.3.2",
"expo-cli": "^4.0.17",
@@ -23,7 +25,8 @@
"react-native": "0.71.14",
"react-native-swipeout": "^2.3.6",
"react-native-vector-icons": "^10.0.0",
- "react-native-web": "~0.18.11"
+ "react-native-web": "~0.18.11",
+ "tailwind-rn": "^4.2.0"
},
"devDependencies": {
"@babel/core": "^7.20.0",
@@ -32,6 +35,18 @@
"typescript": "^4.9.4"
}
},
+ "node_modules/@alloc/quick-lru": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
+ "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==",
+ "peer": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/@ampproject/remapping": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz",
@@ -4467,6 +4482,17 @@
"read-package-json-fast": "^2.0.1"
}
},
+ "node_modules/@react-native-async-storage/async-storage": {
+ "version": "1.17.11",
+ "resolved": "https://registry.npmjs.org/@react-native-async-storage/async-storage/-/async-storage-1.17.11.tgz",
+ "integrity": "sha512-bzs45n5HNcDq6mxXnSsOHysZWn1SbbebNxldBXCQs8dSvF8Aor9KCdpm+TpnnGweK3R6diqsT8lFhX77VX0NFw==",
+ "dependencies": {
+ "merge-options": "^3.0.4"
+ },
+ "peerDependencies": {
+ "react-native": "^0.0.0-0 || 0.60 - 0.71 || 1000.0.0"
+ }
+ },
"node_modules/@react-native-community/cli": {
"version": "10.2.4",
"resolved": "https://registry.npmjs.org/@react-native-community/cli/-/cli-10.2.4.tgz",
@@ -5628,6 +5654,15 @@
"node": ">=8"
}
},
+ "node_modules/@react-native-community/hooks": {
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/@react-native-community/hooks/-/hooks-2.8.1.tgz",
+ "integrity": "sha512-DCmCIC0Gn9m6K0Mlg2MwNmTxMEpBu5lTLsI6b/XUAv/vLGa6o+X7RhCai4FWeqkjCU36+ZOwaLzDo4NBWMXaoQ==",
+ "peerDependencies": {
+ "react": ">=16.8.0",
+ "react-native": ">=0.59"
+ }
+ },
"node_modules/@react-native/assets": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@react-native/assets/-/assets-1.0.0.tgz",
@@ -5686,9 +5721,9 @@
}
},
"node_modules/@react-navigation/native-stack": {
- "version": "6.9.16",
- "resolved": "https://registry.npmjs.org/@react-navigation/native-stack/-/native-stack-6.9.16.tgz",
- "integrity": "sha512-SrmBGr5YvRxDtdTacOkA/wvqwpt9kt+AsYpmt82hKMPKpu0v98WONedTXDzi6whhY3jeT2GZkwF8hyrJ+wDbTA==",
+ "version": "6.9.17",
+ "resolved": "https://registry.npmjs.org/@react-navigation/native-stack/-/native-stack-6.9.17.tgz",
+ "integrity": "sha512-X8p8aS7JptQq7uZZNFEvfEcPf6tlK4PyVwYDdryRbG98B4bh2wFQYMThxvqa+FGEN7USEuHdv2mF0GhFKfX0ew==",
"dependencies": {
"@react-navigation/elements": "^1.3.21",
"warn-once": "^0.1.0"
@@ -5895,6 +5930,11 @@
"resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz",
"integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA=="
},
+ "node_modules/@types/minimist": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.4.tgz",
+ "integrity": "sha512-Kfe/D3hxHTusnPNRbycJE1N77WHDsdS4AjUYIzlDzhDrS47NrwuL3YW4VITxwR7KCVpzwgy4Rbj829KSSQmwXQ=="
+ },
"node_modules/@types/node": {
"version": "20.8.10",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.10.tgz",
@@ -5903,6 +5943,11 @@
"undici-types": "~5.26.4"
}
},
+ "node_modules/@types/normalize-package-data": {
+ "version": "2.4.3",
+ "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.3.tgz",
+ "integrity": "sha512-ehPtgRgaULsFG8x0NeYJvmyH1hmlfsNLujHe9dQEia/7MAJYdzMSi19JtchUHjmBA6XC/75dK55mzZH+RyieSg=="
+ },
"node_modules/@types/prop-types": {
"version": "15.7.9",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.9.tgz",
@@ -7134,7 +7179,6 @@
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
- "optional": true,
"engines": {
"node": ">=8"
}
@@ -7784,6 +7828,55 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/camelcase-css": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
+ "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==",
+ "peer": true,
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/camelcase-keys": {
+ "version": "6.2.2",
+ "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz",
+ "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==",
+ "dependencies": {
+ "camelcase": "^5.3.1",
+ "map-obj": "^4.0.0",
+ "quick-lru": "^4.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/camelcase-keys/node_modules/camelcase": {
+ "version": "5.3.1",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+ "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/camelcase-keys/node_modules/quick-lru": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz",
+ "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/camelize": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.1.tgz",
+ "integrity": "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/caniuse-api": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz",
@@ -7858,7 +7951,6 @@
"url": "https://paulmillr.com/funding/"
}
],
- "optional": true,
"dependencies": {
"anymatch": "~3.1.2",
"braces": "~3.0.2",
@@ -8784,6 +8876,24 @@
"node": ">=8"
}
},
+ "node_modules/css": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/css/-/css-3.0.0.tgz",
+ "integrity": "sha512-DG9pFfwOrzc+hawpmqX/dHYHJG+Bsdb0klhyi1sDneOgGOXy9wQIC8hzyVp1e4NRYDBdxcylvywPkkXCHAzTyQ==",
+ "dependencies": {
+ "inherits": "^2.0.4",
+ "source-map": "^0.6.1",
+ "source-map-resolve": "^0.6.0"
+ }
+ },
+ "node_modules/css-color-keywords": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz",
+ "integrity": "sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==",
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/css-color-names": {
"version": "0.0.4",
"resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz",
@@ -8891,6 +9001,11 @@
"url": "https://opencollective.com/webpack"
}
},
+ "node_modules/css-mediaquery": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/css-mediaquery/-/css-mediaquery-0.1.2.tgz",
+ "integrity": "sha512-COtn4EROW5dBGlE/4PiKnh6rZpAPxDeFLaEEwt4i10jpDMFt2EhQGS79QmmrO+iKCHv0PU/HrOWEhijFd1x99Q=="
+ },
"node_modules/css-select": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz",
@@ -8925,6 +9040,16 @@
"url": "https://github.com/fb55/domhandler?sponsor=1"
}
},
+ "node_modules/css-to-react-native": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.2.0.tgz",
+ "integrity": "sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==",
+ "dependencies": {
+ "camelize": "^1.0.0",
+ "css-color-keywords": "^1.0.0",
+ "postcss-value-parser": "^4.0.2"
+ }
+ },
"node_modules/css-tree": {
"version": "1.0.0-alpha.37",
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz",
@@ -8956,6 +9081,24 @@
"url": "https://github.com/sponsors/fb55"
}
},
+ "node_modules/css/node_modules/source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/css/node_modules/source-map-resolve": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.6.0.tgz",
+ "integrity": "sha512-KXBr9d/fO/bWo97NXsPIAW1bFSBOuCnjbNTBMO7N59hsv5i9yzRDfcYwwt0l04+VqnKC+EwzvJZIP/qkuMgR/w==",
+ "deprecated": "See https://github.com/lydell/source-map-resolve#deprecated",
+ "dependencies": {
+ "atob": "^2.1.2",
+ "decode-uri-component": "^0.2.0"
+ }
+ },
"node_modules/cssesc": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
@@ -9119,6 +9262,21 @@
"node": ">=0.10"
}
},
+ "node_modules/date-fns": {
+ "version": "2.30.0",
+ "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz",
+ "integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==",
+ "dependencies": {
+ "@babel/runtime": "^7.21.0"
+ },
+ "engines": {
+ "node": ">=0.11"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/date-fns"
+ }
+ },
"node_modules/dateformat": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz",
@@ -9164,6 +9322,29 @@
"node": ">=0.10.0"
}
},
+ "node_modules/decamelize-keys": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz",
+ "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==",
+ "dependencies": {
+ "decamelize": "^1.1.0",
+ "map-obj": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/decamelize-keys/node_modules/map-obj": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz",
+ "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/decode-uri-component": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz",
@@ -9445,6 +9626,12 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
},
+ "node_modules/didyoumean": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
+ "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==",
+ "peer": true
+ },
"node_modules/diffie-hellman": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz",
@@ -9471,6 +9658,12 @@
"node": ">=8"
}
},
+ "node_modules/dlv": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
+ "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==",
+ "peer": true
+ },
"node_modules/dns-equal": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz",
@@ -9650,9 +9843,9 @@
"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
},
"node_modules/electron-to-chromium": {
- "version": "1.4.574",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.574.tgz",
- "integrity": "sha512-bg1m8L0n02xRzx4LsTTMbBPiUd9yIR+74iPtS/Ao65CuXvhVZHP0ym1kSdDG3yHFDXqHQQBKujlN1AQ8qZnyFg=="
+ "version": "1.4.576",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.576.tgz",
+ "integrity": "sha512-yXsZyXJfAqzWk1WKryr0Wl0MN2D47xodPvEEwlVePBnhU5E7raevLQR+E6b9JAD3GfL/7MbAL9ZtWQQPcLx7wA=="
},
"node_modules/elliptic": {
"version": "6.5.4",
@@ -12826,6 +13019,14 @@
"node": ">=6"
}
},
+ "node_modules/hard-rejection": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz",
+ "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/has": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz",
@@ -13860,7 +14061,6 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
- "optional": true,
"dependencies": {
"binary-extensions": "^2.0.0"
},
@@ -14142,6 +14342,14 @@
"node": ">=8"
}
},
+ "node_modules/is-plain-obj": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz",
+ "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/is-plain-object": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
@@ -15094,6 +15302,15 @@
"resolved": "https://registry.npmjs.org/jimp-compact/-/jimp-compact-0.16.1.tgz",
"integrity": "sha512-dZ6Ra7u1G8c4Letq/B5EzAxj4tLFHL+cGtdpR+PVm4yzPDj+lCk+AbivWt1eOM+ikzkowtyV7qSqX6qr3t71Ww=="
},
+ "node_modules/jiti": {
+ "version": "1.21.0",
+ "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz",
+ "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==",
+ "peer": true,
+ "bin": {
+ "jiti": "bin/jiti.js"
+ }
+ },
"node_modules/joi": {
"version": "17.11.0",
"resolved": "https://registry.npmjs.org/joi/-/joi-17.11.0.tgz",
@@ -15446,6 +15663,15 @@
"node": ">=6"
}
},
+ "node_modules/lilconfig": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz",
+ "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==",
+ "peer": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/lines-and-columns": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
@@ -15675,6 +15901,17 @@
"node": ">=0.10.0"
}
},
+ "node_modules/map-obj": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz",
+ "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/map-visit": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz",
@@ -15757,11 +15994,65 @@
"readable-stream": "^2.0.1"
}
},
+ "node_modules/meow": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/meow/-/meow-7.1.1.tgz",
+ "integrity": "sha512-GWHvA5QOcS412WCo8vwKDlTelGLsCGBVevQB5Kva961rmNfun0PCbv5+xta2kUMFJyR8/oWnn7ddeKdosbAPbA==",
+ "dependencies": {
+ "@types/minimist": "^1.2.0",
+ "camelcase-keys": "^6.2.2",
+ "decamelize-keys": "^1.1.0",
+ "hard-rejection": "^2.1.0",
+ "minimist-options": "4.1.0",
+ "normalize-package-data": "^2.5.0",
+ "read-pkg-up": "^7.0.1",
+ "redent": "^3.0.0",
+ "trim-newlines": "^3.0.0",
+ "type-fest": "^0.13.1",
+ "yargs-parser": "^18.1.3"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/meow/node_modules/type-fest": {
+ "version": "0.13.1",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz",
+ "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/merge-descriptors": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
"integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w=="
},
+ "node_modules/merge-options": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/merge-options/-/merge-options-3.0.4.tgz",
+ "integrity": "sha512-2Sug1+knBjkaMsMgf1ctR1Ujx+Ayku4EdJN4Z+C2+JzoeF7A3OZ9KM2GY0CpQS51NR61LTurMJrRKPhSs3ZRTQ==",
+ "dependencies": {
+ "is-plain-obj": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/merge-options/node_modules/is-plain-obj": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
+ "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/merge-stream": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
@@ -16676,6 +16967,14 @@
"node": ">=4"
}
},
+ "node_modules/min-indent": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz",
+ "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==",
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/mini-css-extract-plugin": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.5.0.tgz",
@@ -16758,6 +17057,27 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/minimist-options": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz",
+ "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==",
+ "dependencies": {
+ "arrify": "^1.0.1",
+ "is-plain-obj": "^1.1.0",
+ "kind-of": "^6.0.3"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/minimist-options/node_modules/arrify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz",
+ "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/minipass": {
"version": "3.1.6",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.6.tgz",
@@ -17316,6 +17636,30 @@
"resolved": "https://registry.npmjs.org/normalize-css-color/-/normalize-css-color-1.0.2.tgz",
"integrity": "sha512-jPJ/V7Cp1UytdidsPqviKEElFQJs22hUUgK5BOPHTwOonNCk7/2qOxhhqzEajmFrWJowADFfOFh1V+aWkRfy+w=="
},
+ "node_modules/normalize-package-data": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
+ "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
+ "dependencies": {
+ "hosted-git-info": "^2.1.4",
+ "resolve": "^1.10.0",
+ "semver": "2 || 3 || 4 || 5",
+ "validate-npm-package-license": "^3.0.1"
+ }
+ },
+ "node_modules/normalize-package-data/node_modules/hosted-git-info": {
+ "version": "2.8.9",
+ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz",
+ "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw=="
+ },
+ "node_modules/normalize-package-data/node_modules/semver": {
+ "version": "5.7.2",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
+ "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
+ "bin": {
+ "semver": "bin/semver"
+ }
+ },
"node_modules/normalize-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
@@ -17674,6 +18018,15 @@
"node": ">=0.10.0"
}
},
+ "node_modules/object-hash": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz",
+ "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==",
+ "peer": true,
+ "engines": {
+ "node": ">= 6"
+ }
+ },
"node_modules/object-inspect": {
"version": "1.13.1",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz",
@@ -20378,6 +20731,24 @@
"tween-functions": "^1.0.1"
}
},
+ "node_modules/read-cache": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
+ "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==",
+ "peer": true,
+ "dependencies": {
+ "pify": "^2.3.0"
+ }
+ },
+ "node_modules/read-cache/node_modules/pify": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
+ "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
+ "peer": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/read-chunk": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/read-chunk/-/read-chunk-3.2.0.tgz",
@@ -20410,6 +20781,125 @@
"node": ">=10"
}
},
+ "node_modules/read-pkg": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz",
+ "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==",
+ "dependencies": {
+ "@types/normalize-package-data": "^2.4.0",
+ "normalize-package-data": "^2.5.0",
+ "parse-json": "^5.0.0",
+ "type-fest": "^0.6.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/read-pkg-up": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz",
+ "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==",
+ "dependencies": {
+ "find-up": "^4.1.0",
+ "read-pkg": "^5.2.0",
+ "type-fest": "^0.8.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/read-pkg-up/node_modules/find-up": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+ "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+ "dependencies": {
+ "locate-path": "^5.0.0",
+ "path-exists": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/read-pkg-up/node_modules/locate-path": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+ "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+ "dependencies": {
+ "p-locate": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/read-pkg-up/node_modules/p-limit": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+ "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+ "dependencies": {
+ "p-try": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/read-pkg-up/node_modules/p-locate": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+ "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+ "dependencies": {
+ "p-limit": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/read-pkg-up/node_modules/path-exists": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+ "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/read-pkg-up/node_modules/type-fest": {
+ "version": "0.8.1",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
+ "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/read-pkg/node_modules/parse-json": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
+ "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
+ "dependencies": {
+ "@babel/code-frame": "^7.0.0",
+ "error-ex": "^1.3.1",
+ "json-parse-even-better-errors": "^2.3.0",
+ "lines-and-columns": "^1.1.6"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/read-pkg/node_modules/type-fest": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz",
+ "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/readable-stream": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
@@ -20428,7 +20918,6 @@
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
- "optional": true,
"dependencies": {
"picomatch": "^2.2.1"
},
@@ -20485,6 +20974,18 @@
"node": "*"
}
},
+ "node_modules/redent": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz",
+ "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==",
+ "dependencies": {
+ "indent-string": "^4.0.0",
+ "strip-indent": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/regenerate": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
@@ -21767,6 +22268,15 @@
"node": ">= 8"
}
},
+ "node_modules/source-map-js": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
+ "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
+ "peer": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/source-map-resolve": {
"version": "0.5.3",
"resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz",
@@ -21803,6 +22313,34 @@
"integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==",
"deprecated": "See https://github.com/lydell/source-map-url#deprecated"
},
+ "node_modules/spdx-correct": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz",
+ "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==",
+ "dependencies": {
+ "spdx-expression-parse": "^3.0.0",
+ "spdx-license-ids": "^3.0.0"
+ }
+ },
+ "node_modules/spdx-exceptions": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz",
+ "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A=="
+ },
+ "node_modules/spdx-expression-parse": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz",
+ "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==",
+ "dependencies": {
+ "spdx-exceptions": "^2.1.0",
+ "spdx-license-ids": "^3.0.0"
+ }
+ },
+ "node_modules/spdx-license-ids": {
+ "version": "3.0.16",
+ "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.16.tgz",
+ "integrity": "sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw=="
+ },
"node_modules/spdy": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz",
@@ -22176,6 +22714,17 @@
"node": ">=0.10.0"
}
},
+ "node_modules/strip-indent": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz",
+ "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==",
+ "dependencies": {
+ "min-indent": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/strip-json-comments": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
@@ -22441,6 +22990,197 @@
"node": ">=0.10.0"
}
},
+ "node_modules/tailwind-rn": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/tailwind-rn/-/tailwind-rn-4.2.0.tgz",
+ "integrity": "sha512-mJpB7v/trQRlkAVV8Kel0Kl66KosvwuXX4/rgZrUL96FL2YFMBc6Y2QUB9sKQBUmemaBB5PQS/IKpV1odm9RCQ==",
+ "dependencies": {
+ "@react-native-community/hooks": "^2.8.1",
+ "chokidar": "^3.5.2",
+ "color-string": "^1.9.0",
+ "css": "^3.0.0",
+ "css-mediaquery": "^0.1.2",
+ "css-to-react-native": "^3.0.0",
+ "meow": "^7.0.1"
+ },
+ "bin": {
+ "tailwind-rn": "dist/cli.js"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "peerDependencies": {
+ "react-native": "*",
+ "tailwindcss": "^3.0.0"
+ }
+ },
+ "node_modules/tailwindcss": {
+ "version": "3.3.5",
+ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.5.tgz",
+ "integrity": "sha512-5SEZU4J7pxZgSkv7FP1zY8i2TIAOooNZ1e/OGtxIEv6GltpoiXUqWvLy89+a10qYTB1N5Ifkuw9lqQkN9sscvA==",
+ "peer": true,
+ "dependencies": {
+ "@alloc/quick-lru": "^5.2.0",
+ "arg": "^5.0.2",
+ "chokidar": "^3.5.3",
+ "didyoumean": "^1.2.2",
+ "dlv": "^1.1.3",
+ "fast-glob": "^3.3.0",
+ "glob-parent": "^6.0.2",
+ "is-glob": "^4.0.3",
+ "jiti": "^1.19.1",
+ "lilconfig": "^2.1.0",
+ "micromatch": "^4.0.5",
+ "normalize-path": "^3.0.0",
+ "object-hash": "^3.0.0",
+ "picocolors": "^1.0.0",
+ "postcss": "^8.4.23",
+ "postcss-import": "^15.1.0",
+ "postcss-js": "^4.0.1",
+ "postcss-load-config": "^4.0.1",
+ "postcss-nested": "^6.0.1",
+ "postcss-selector-parser": "^6.0.11",
+ "resolve": "^1.22.2",
+ "sucrase": "^3.32.0"
+ },
+ "bin": {
+ "tailwind": "lib/cli.js",
+ "tailwindcss": "lib/cli.js"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/tailwindcss/node_modules/arg": {
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
+ "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==",
+ "peer": true
+ },
+ "node_modules/tailwindcss/node_modules/glob-parent": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+ "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
+ "peer": true,
+ "dependencies": {
+ "is-glob": "^4.0.3"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/tailwindcss/node_modules/postcss": {
+ "version": "8.4.31",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
+ "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/postcss"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "peer": true,
+ "dependencies": {
+ "nanoid": "^3.3.6",
+ "picocolors": "^1.0.0",
+ "source-map-js": "^1.0.2"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ }
+ },
+ "node_modules/tailwindcss/node_modules/postcss-import": {
+ "version": "15.1.0",
+ "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz",
+ "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==",
+ "peer": true,
+ "dependencies": {
+ "postcss-value-parser": "^4.0.0",
+ "read-cache": "^1.0.0",
+ "resolve": "^1.1.7"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "peerDependencies": {
+ "postcss": "^8.0.0"
+ }
+ },
+ "node_modules/tailwindcss/node_modules/postcss-js": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz",
+ "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==",
+ "peer": true,
+ "dependencies": {
+ "camelcase-css": "^2.0.1"
+ },
+ "engines": {
+ "node": "^12 || ^14 || >= 16"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ "peerDependencies": {
+ "postcss": "^8.4.21"
+ }
+ },
+ "node_modules/tailwindcss/node_modules/postcss-load-config": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.1.tgz",
+ "integrity": "sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==",
+ "peer": true,
+ "dependencies": {
+ "lilconfig": "^2.0.5",
+ "yaml": "^2.1.1"
+ },
+ "engines": {
+ "node": ">= 14"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ "peerDependencies": {
+ "postcss": ">=8.0.9",
+ "ts-node": ">=9.0.0"
+ },
+ "peerDependenciesMeta": {
+ "postcss": {
+ "optional": true
+ },
+ "ts-node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/tailwindcss/node_modules/postcss-nested": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz",
+ "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==",
+ "peer": true,
+ "dependencies": {
+ "postcss-selector-parser": "^6.0.11"
+ },
+ "engines": {
+ "node": ">=12.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ "peerDependencies": {
+ "postcss": "^8.2.14"
+ }
+ },
"node_modules/tapable": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz",
@@ -22997,6 +23737,14 @@
"tree-kill": "cli.js"
}
},
+ "node_modules/trim-newlines": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz",
+ "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==",
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/ts-interface-checker": {
"version": "0.1.13",
"resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
@@ -23666,6 +24414,15 @@
"resolved": "https://registry.npmjs.org/valid-url/-/valid-url-1.0.9.tgz",
"integrity": "sha512-QQDsV8OnSf5Uc30CKSwG9lnhMPe6exHtTXLRYX8uMwKENy640pU+2BgBL0LRbDh/eYRahNCS7aewCx0wf3NYVA=="
},
+ "node_modules/validate-npm-package-license": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
+ "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
+ "dependencies": {
+ "spdx-correct": "^3.0.0",
+ "spdx-expression-parse": "^3.0.0"
+ }
+ },
"node_modules/validate-npm-package-name": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz",
@@ -26209,6 +26966,15 @@
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="
},
+ "node_modules/yaml": {
+ "version": "2.3.4",
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz",
+ "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==",
+ "peer": true,
+ "engines": {
+ "node": ">= 14"
+ }
+ },
"node_modules/yargs": {
"version": "15.4.1",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
diff --git a/client/package.json b/client/package.json
index 7ae3d6beaa69e06fde9d3b890063af2f789d59ee..cba85d7a1372e429e6bd1de3fd859421cd2575c2 100644
--- a/client/package.json
+++ b/client/package.json
@@ -9,10 +9,12 @@
"web": "expo start --web"
},
"dependencies": {
+ "@react-native-async-storage/async-storage": "1.17.11",
"@react-navigation/native": "^6.1.9",
"@react-navigation/native-stack": "^6.9.16",
"@react-navigation/stack": "^6.3.20",
"@stripe/stripe-react-native": "0.23.3",
+ "date-fns": "^2.30.0",
"expo": "^48.0.0",
"expo-barcode-scanner": "~12.3.2",
"expo-cli": "^4.0.17",
@@ -24,7 +26,8 @@
"react-native": "0.71.14",
"react-native-swipeout": "^2.3.6",
"react-native-vector-icons": "^10.0.0",
- "react-native-web": "~0.18.11"
+ "react-native-web": "~0.18.11",
+ "tailwind-rn": "^4.2.0"
},
"devDependencies": {
"@babel/core": "^7.20.0",
diff --git a/client/screens/CartScreen.tsx b/client/screens/CartScreen.tsx
index e36c0e87a5cee2118bb6674d3296fffd3ce904f8..b823a7255fc8fbb4ff76a4b24e11b61ac66737fa 100644
--- a/client/screens/CartScreen.tsx
+++ b/client/screens/CartScreen.tsx
@@ -1,42 +1,64 @@
import React, { useEffect, useState } from 'react';
-import { View, Text, Button, FlatList } from 'react-native';
-import { useNavigation } from '@react-navigation/native';
-import Styles from '../styles/Style';
-import Icon from 'react-native-vector-icons/MaterialIcons';
-import db from '../database/db';
-import Constants from 'expo-constants';
-import Swipeout from 'react-native-swipeout';
+ import { View, Text, Button, FlatList } from 'react-native';
+ import { useNavigation } from '@react-navigation/native';
+ import Styles from '../styles/Style';
+ import Icon from 'react-native-vector-icons/MaterialIcons';
+ import Swipeout from 'react-native-swipeout';
+ import AsyncStorage from '@react-native-async-storage/async-storage';
+ import Constants from 'expo-constants';
+ import {
+ getItemsWithQuantities,
+ deleteItem,
+ increaseQuantity,
+ decreaseQuantity
+ } from '../database/dbUtils';
-function CartScreen() {
- const navigation = useNavigation();
- const [items, setItems] = useState([]);
- const [totalPrice, setTotalPrice] = useState(0);
+ export default function CartScreen() {
+ const navigation = useNavigation();
+ const [items, setItems] = useState([]);
+ const [totalPrice, setTotalPrice] = useState(0);
+ const apiUrl = Constants.manifest.extra.apiUrl;
+ const [isDarkMode, setIsDarkMode] = useState(false);
- const apiUrl = Constants.manifest.extra.apiUrl;
+ const retrieveThemeMode = async () => {
+ try {
+ const themeMode = await AsyncStorage.getItem('themeMode');
+ if (themeMode !== null) {
+ setIsDarkMode(themeMode === 'dark');
+ }
+ } catch (error) {
+ console.log('Error retrieving theme mode:', error);
+ }
+ };
- const getItemsWithQuantities = () => {
- return new Promise((resolve, reject) => {
- db.transaction((tx) => {
- tx.executeSql('SELECT * FROM items', [], (_, { rows }) => {
- const items = rows._array;
- resolve(items);
- });
- });
- });
+ const toggleTheme = () => {
+ const newThemeMode = !isDarkMode;
+ setIsDarkMode(newThemeMode);
+ AsyncStorage.setItem('themeMode', newThemeMode ? 'dark' : 'light');
+ };
+
+ useEffect(() => {
+ retrieveThemeMode();
+ updateCart();
+ }, []);
+
+ const updateCart = async () => {
+ try {
+ const itemsData = await getItemsWithQuantities();
+ setItems(itemsData);
+ calculateTotalPrice(itemsData);
+ } catch (error) {
+ console.log('Error fetching data:', error);
+ }
};
- useEffect(() => {
- getItemsWithQuantities().then((items) => {
- setItems(items);
- calculateTotalPrice(items);
- });
- }, []);
const calculateTotalPrice = (items) => {
const cartItems = items.map((item) => ({
item_id: item.id,
quantity: item.quantity,
}));
+ console.log(items);
const requestOptions = {
method: 'POST',
headers: {
@@ -52,67 +74,65 @@ function CartScreen() {
return response.json();
})
.then((total) => {
+ console.log(total);
setTotalPrice((total / 100).toFixed(2));
})
.catch((error) => {
- console.error('Error calculating total:', error);
+ console.log('Error calculating total:', error);
});
};
- const deleteItem = (itemId) => {
- db.transaction((tx) => {
- tx.executeSql(
- 'DELETE FROM items WHERE id = ?',
- [itemId],
- () => {
- // Update the list of items after deletion
- const updatedItems = items.filter((item) => item.id !== itemId);
- setItems(updatedItems);
- calculateTotalPrice(updatedItems);
- },
- (error) => {
- console.error('Error deleting item from items:', error);
- }
- );
- });
- };
-
- const renderItem = ({ item }) => {
- const swipeoutBtns = [
- {
- text: 'Delete',
- backgroundColor: 'red',
- onPress: () => deleteItem(item.id),
- },
- ];
+ const swipeoutBtns = (item) => [{
+ text: 'Delete',
+ backgroundColor: 'red',
+ onPress: () => {
+ if (item && item.id) {
+ deleteItem(item.id).then(() => {
+ updateCart();
+ });
+ }
+ },
+ }];
- return (
-
-
-
- {item.name} ({item.quantity})
-
- {(item.price / 100).toFixed(2)} €
-
-
- );
- };
+ const renderItem = ({ item }) => {
+ return (
+
+
+
+ {item.name}
+ ({item.quantity})
+
+ {(item.price / 100).toFixed(2)} €
+
+
+
+
+ );
+ };
return (
-
-
- Basket
-
+
item.id.toString()}
/>
- Total:
- {totalPrice} €
+ Total:
+ {totalPrice} €
navigation.navigate('Checkout', { items: items, totalPrice: totalPrice })}
/>
diff --git a/client/CheckoutScreen.tsx b/client/screens/CheckoutScreen.tsx
similarity index 58%
rename from client/CheckoutScreen.tsx
rename to client/screens/CheckoutScreen.tsx
index 83e008bc501b6f92be63586c1f390a139623a375..5dbe22595722c06022dc282439e878ecd314dac3 100644
--- a/client/CheckoutScreen.tsx
+++ b/client/screens/CheckoutScreen.tsx
@@ -4,6 +4,9 @@ import React, { useEffect, useState } from "react";
import { Alert, Text, Button, SafeAreaView, View } from "react-native";
import BasketScreen from './screens/BasketScreen';
import * as SQLite from 'expo-sqlite';
+import {
+deleteItem,
+} from '../database/dbUtils';
export default function CheckoutScreen({ route }) {
const { initPaymentSheet, presentPaymentSheet } = useStripe();
@@ -65,50 +68,6 @@ export default function CheckoutScreen({ route }) {
}
};
- const moveItemsToHistory = (itemIds) => {
- db.transaction((tx) => {
- const currentDate = new Date().toISOString();
-
- itemIds.forEach((itemId) => {
- // we fetch the item details from the "items" table
- tx.executeSql(
- 'SELECT * FROM items WHERE id = ?',
- [itemId],
- (_, { rows }) => {
- const item = rows._array[0];
- if (item) {
- // we insert the item into the "history" table with the current date
- tx.executeSql(
- 'INSERT INTO history (name, price, date) VALUES (?, ?, ?)',
- [item.name, item.price, currentDate],
- (_, results) => {
- console.log(`Item '${item.name}' moved to history`);
- },
- (_, error) => {
- console.error('Error inserting item into history:', error);
- }
- );
- // we delete the item from the "items" table
- tx.executeSql(
- 'DELETE FROM items WHERE id = ?',
- [itemId],
- (_, results) => {
- console.log(`Item '${item.name}' deleted from items`);
- },
- (_, error) => {
- console.error('Error deleting item from items:', error);
- }
- );
- }
- },
- (error) => {
- console.error('Error fetching item from items:', error);
- }
- );
- });
- });
- };
-
const openPaymentSheet = async () => {
const { error } = await presentPaymentSheet();
@@ -127,8 +86,10 @@ export default function CheckoutScreen({ route }) {
});
if (response.status === 200) {
- // we move items to history on successful payment
- moveItemsToHistory(items.map((item) => item.id));
+ for (const item of items) {
+ console.log('Deleting item:', item);
+ await deleteItem(item.id);
+ }
Alert.alert('Success', 'Your order is confirmed!');
}
}
@@ -140,7 +101,6 @@ export default function CheckoutScreen({ route }) {
return (
- Payment
{
+ try {
+ const themeMode = await AsyncStorage.getItem('themeMode');
+ if (themeMode !== null) {
+ setIsDarkMode(themeMode === 'dark');
+ }
+ } catch (error) {
+ console.log('Error retrieving theme mode:', error);
+ }
+ };
+
+ useEffect(() => {
+ retrieveThemeMode();
+ loadPaymentHistory();
+ }, []);
+
+ const loadPaymentHistory = async () => {
+ try {
+ const response = await fetch(`${apiUrl}/payments/${customerId}`);
+ if (response.ok) {
+ const history = await response.json();
+ setPaymentHistory(history);
+ } else {
+ console.log('Error while retrieving payments history');
+ }
+ } catch (error) {
+ console.log('Error while retrieving payments history', error);
+ }
+ };
+
+ return (
+
+ item.id}
+ renderItem={({ item }) => (
+
+ {item.purchased_items[0].item.name}
+
+ {format(new Date(item.checkout_date), 'MMMM dd, yyyy HH:mm a')}
+
+
+ {(item.purchased_items[0].item.price / 100).toFixed(2)} €
+
+
+ )}
+ />
+
+ );
+}
diff --git a/client/screens/ScanScreen.tsx b/client/screens/ScanScreen.tsx
index e52564cce867c49143e73f2f16ba75d2ed55024d..3d5e87f2d89b9be638bdf8801d3b337d9cecee16 100644
--- a/client/screens/ScanScreen.tsx
+++ b/client/screens/ScanScreen.tsx
@@ -1,24 +1,34 @@
import React, { useState, useEffect } from 'react';
-import { Text, View, StyleSheet, Button, TextInput } from 'react-native';
+import { Text, View, StyleSheet, TouchableOpacity, TextInput, Button, Alert } from 'react-native';
import { BarCodeScanner } from 'expo-barcode-scanner';
import Constants from 'expo-constants';
import { ImageBackground } from 'react-native';
import Styles from '../styles/Style';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { useNavigation } from '@react-navigation/native';
-import db from '../database/db';
+import Icon from 'react-native-vector-icons/MaterialIcons';
+ import {
+ updateLocalItemQuantity,
+ checkIfLocalItemExists,
+ insertItem,
+ } from '../database/dbUtils';
export default function App() {
const [hasPermission, setHasPermission] = useState(false);
const [scanned, setScanned] = useState(false);
const [manualEntry, setManualEntry] = useState(false);
const [barcodeData, setBarcodeData] = useState('');
- const [itemName, setItemName] = useState('');
- const [itemPrice, setItemPrice] = useState('');
+ const [item, setItem] = useState();
const navigation = useNavigation();
+ const [isDarkMode, setIsDarkMode] = useState(false);
useEffect(() => {
const getBarCodeScannerPermissions = async () => {
+ const storedThemeMode = await AsyncStorage.getItem('themeMode');
+ if (storedThemeMode) {
+ setIsDarkMode(storedThemeMode === 'dark');
+ }
+
const { status } = await BarCodeScanner.requestPermissionsAsync();
const isPermissionGranted = status === 'granted';
setHasPermission(isPermissionGranted);
@@ -30,197 +40,93 @@ export default function App() {
getBarCodeScannerPermissions();
}, []);
- const extractDataFromBarcode = (data) => {
- const [name, price] = data.split('-');
- console.log('extract : ', name, ' ', price);
- checkItemExistence(name, price);
- };
-
- const sendPostRequest = (name,price) => {
- const apiUrl = Constants.expoConfig.extra.apiUrl;
-
- const newItem = {
- name: name,
- price: parseInt(price),
- };
- console.log(newItem);
- fetch(`${apiUrl}/items/`, {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify(newItem),
- })
- .then((response) => {
- if (!response.ok) {
- throw new Error('response not valid');
- }
- return response.json();
- })
- .then((data) => {
- console.log('Item added:', data);
- alert('The item has been added to the basket');
- const ItemId = data.id;
- addLocalItem(ItemId, name, price);
- setItemName('');
- setItemPrice('');
- })
- .catch((error) => {
- console.error('Error requesting the API:', error);
- });
- };
-
- const addLocalItem = (apiId, name, price) => {
- checkIfLocalItemExists(apiId)
- .then((existingItem) => {
- if (existingItem) {
- console.log('existing')
- // L'article existe déjà, on met à jour la quantité
- const newQuantity = existingItem.quantity + 1;
- db.transaction((tx) => {
- tx.executeSql(
- 'UPDATE items SET quantity = ? WHERE id = ?',
- [newQuantity, apiId],
- (_, results) => {
- console.log(`Item ${name} updated in local db (quantity: ${newQuantity})`);
- },
- (_, error) => {
- console.log('Error updating item in local database:', error);
- }
- );
- });
- } else {
- console.log('on insere')
- // L'article n'existe pas encore, on insère un nouvel enregistrement avec une quantité initiale de 1
- db.transaction((tx) => {
- tx.executeSql(
- 'INSERT INTO items (id, name, price, quantity) VALUES (?, ?, ?, ?)',
- [apiId, name, price, 1], // La quantité initiale est définie à 1
- (_, results) => {
- console.log(`Item ${name} added in local db (quantity: 1)`);
- },
- (_, error) => {
- console.log('Error adding item to local database:', error);
- }
- );
- });
- }
- })
- .catch((error) => {
- console.log('Error checking item existence in local database:', error);
- });
- };
-
- const checkIfLocalItemExists = (apiId) => {
- return new Promise((resolve, reject) => {
- db.transaction((tx) => {
- tx.executeSql(
- 'SELECT * FROM items WHERE id = ?',
- [apiId],
- (_, { rows: { _array } }) => {
- if (_array.length > 0) {
- resolve(_array[0]);
- } else {
- resolve(null);
- }
- },
- (_, error) => {
- reject(error);
- }
- );
- });
- });
+ const toggleTheme = () => {
+ const newThemeMode = !isDarkMode;
+ setIsDarkMode(newThemeMode);
+ AsyncStorage.setItem('themeMode', newThemeMode ? 'dark' : 'light');
};
-
- const checkItemExistence = async (name, price) => {
+ const checkItemExistence = async (itemId) => {
const apiUrl = Constants.expoConfig.extra.apiUrl;
- console.log('item name :', name);
try {
- const response = await fetch(`${apiUrl}/items/check-existence?item_name=${name}`, {
- method: 'GET',
- headers: {
- 'Content-Type': 'application/json',
- }
- });
-
- if (!response.ok) {
- throw new Error('Response not valid');
- }
-
- const data = await response.json();
-
- if (data.exists) {
- alert('Item already exists in the database');
-
- if (data.item_id) {
- const existingItem = await checkIfLocalItemExists(data.item_id);
+ const apiUrl = Constants.expoConfig.extra.apiUrl;
+ const response = await fetch(`${apiUrl}/items/${itemId}`, {
+ method: 'GET',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ });
+ if (response.ok) {
+ const item = await response.json();
+ const existingItem = await checkIfLocalItemExists(item.id);
if (existingItem) {
- const newQuantity = existingItem.quantity + 1;
- db.transaction((tx) => {
- tx.executeSql(
- 'UPDATE items SET quantity = ? WHERE id = ?',
- [newQuantity, data.item_id],
- (_, results) => {
- console.log(`Item ${name} updated in local db (quantity: ${newQuantity})`);
- },
- (_, error) => {
- console.log('Error updating item in local database:', error);
- }
- );
- });
+ const newQuantity = existingItem.quantity + 1;
+ await updateLocalItemQuantity(item.id, newQuantity);
} else {
- addLocalItem(data.item_id, name, price);
+ await insertItem(item.id, item.name, item.price);
}
+
+ alert('Item added to the cart');
} else {
- console.error('Item ID is missing in the response');
+ alert('Item does not exist in the database');
}
- } else {
- sendPostRequest(name, price);
+ } catch (error) {
+ console.log('Error checking item existence:', error);
}
- } catch (error) {
- console.error('Error checking item existence:', error);
- }
};
-
const handleBarCodeScanned = ({ type, data }) => {
setScanned(true);
- alert(`Bar code with type ${type} and data ${data} has been scanned!`);
setBarcodeData(data);
- extractDataFromBarcode(data);
+ checkItemExistence(data);
};
- const handleAddToBasket = async () => {
- setScanned(true);
- await extractDataFromBarcode(barcodeData);
- sendPostRequest();
+ const handleManualEntry = () => {
+ if (barcodeData) {
+ checkItemExistence(barcodeData);
+ } else {
+ Alert.alert('Item Code is required');
+ }
};
return (
-
+
{manualEntry === false ? (
- <>
-
+ setManualEntry(true)}
- style={Styles.topButton}
- />
-
+ Enter manually
+
+ navigation.navigate('PaymentHistoryScreen')}
+ >
+ Payments History
+
+ navigation.navigate('CartScreen')}
- style={Styles.topButton}
- />
- >
+ >
+ Cart
+
+
) : hasPermission === null ? (
Requesting camera permission
) : hasPermission === false ? (
No access to camera
) : null}
- { manualEntry === true ? (
+ {manualEntry === true ? (
- Barcode Data:
+ Item Code:
setBarcodeData(text)}
/>
-
- setManualEntry(false)} />
+
+ setManualEntry(false)}
+ style={Styles.roundedButton}
+ color='#E0A228'
+ />
@@ -247,11 +163,32 @@ export default function App() {
onBarCodeScanned={scanned ? undefined : handleBarCodeScanned}
style={StyleSheet.absoluteFillObject}
/>
- {scanned && setScanned(false)} />}
+ {scanned && (
+ setScanned(false)}
+ style={isDarkMode ? Styles.toggleButton : Styles.inactiveToggleButton}
+ >
+
+ Tap to Scan Again
+
+
+ )}
- )
- }
+ )}
+
+
+
+
+
+
+
+
);
-
}
diff --git a/client/styles/Style.js b/client/styles/Style.js
index 24f6ad21571f6586de4703c1fbfef5080cd03b15..4f1e09250c7bfeb91eef05679afed133912de88d 100644
--- a/client/styles/Style.js
+++ b/client/styles/Style.js
@@ -1,28 +1,89 @@
import { StyleSheet } from 'react-native';
const Styles = StyleSheet.create({
- container: {
- flex: 1,
- justifyContent: 'center',
-},
-barcodeScannerContainer: {
- flex: 1,
- width: '100%',
- height: '50%',
- justifyContent: 'center',
- alignItems: 'center',
-},
-topButton: {
- position: 'absolute',
- backgroundColor: '#E2A755',
- color: 'white',
- marginTop: 0
-},
+ darkContainer: {
+ flex: 1,
+ justifyContent: 'center',
+ backgroundColor: '#1c2155',
+ color: 'white'
+ },
+ darkText: {
+ color: 'white',
+ alignItems: 'center',
+ fontSize: 20
+ },
+ flatList: {
+ flex: 1,
+ margin: 10,
+ borderWidth: 1,
+ borderRadius: 5,
+ },
+ lightContainer: {
+ flex: 1,
+ justifyContent: 'center',
+ backgroundColor: 'white',
+ marginBottom: 10,
+ color: '#1c2155'
+ },
+ lightText: {
+ color: '#1c2155',
+ alignItems: 'center',
+ fontSize: 20,
+ padding:10
+ },
+ lightTitle: {
+ color: '#1c2155',
+ alignItems: 'center',
+ fontSize: 30,
+ padding:10
+ },
+ darkTitle: {
+ color: 'white',
+ alignItems: 'center',
+ fontSize: 30
+ },
+ barcodeScannerContainer: {
+ flex: 1,
+ width: '100%',
+ height: '50%',
+ justifyContent: 'center',
+ alignItems: 'center',
+ },
+ topButton: {
+ position: 'absolute',
+ backgroundColor: '#E2A755',
+ color: 'white',
+ margin: 5,
+ borderRadius: 10,
+ },
+ buttonGroup: {
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ marginBottom: 20,
+ marginTop: 10
+ },
title: {
fontSize: 20,
fontWeight: 'bold',
marginBottom: 16,
+ alignItems: 'center',
+ paddingLeft: '30%',
+ color: 'white',
},
+ roundedButton: {
+ padding: 16,
+ borderRadius: 15,
+ },
+ buttonContainer: {
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ marginBottom: 20,
+ },
+ roundedButton: {
+ flex: 1,
+ marginHorizontal: 5,
+ borderRadius: 10,
+ },
itemRow: {
flexDirection: 'row',
justifyContent: 'space-between',
@@ -35,14 +96,20 @@ topButton: {
borderWidth: 1,
borderColor: 'black',
padding: 5,
- margin: 5
+ margin: 5,
},
totalText: {
fontSize: 16,
},
noCameraMessage: {
- marginTop : 0
+ marginTop: 0,
},
+ quantityButtons: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ justifyContent: 'space-between',
+ margin: 10,
+ },
cardContainer: {
flex: 2,
justifyContent: 'center',
@@ -66,28 +133,61 @@ topButton: {
marginBottom: 10,
},
cardBackground: {
- flex: 1,
- resizeMode: 'cover',
- justifyContent: 'center',
- alignItems: 'center',
- zIndex: 0,
+ flex: 1,
+ resizeMode: 'cover',
+ justifyContent: 'center',
+ alignItems: 'center',
+ zIndex: 0,
},
itemRow: {
flexDirection: 'row',
justifyContent: 'space-between',
marginBottom: 8,
},
+ historyItem: {
+ backgroundColor: '#f5b841',
+ padding: 16,
+ marginBottom: 8,
+ borderRadius: 15,
+ },
itemName: {
- fontSize: 18,
+ fontSize: 20,
+ marginTop: 10,
+ fontWeight: 'bold',
},
- itemQuantity: {
+ itemDate: {
fontSize: 16,
- color: 'gray',
},
itemPrice: {
fontSize: 16,
- color: 'green',
+ marginTop: 15,
+ fontWeight: 'bold',
},
+ toggleButton: {
+ borderRadius: 50,
+ margin: 5,
+ flex: 1,
+ alignItems: 'center',
+ flexDirection: 'row',
+ justifyContent: 'center',
+ },
+ inactiveToggleButton: {
+ borderRadius: 50,
+ margin: 5,
+ flex: 1,
+ alignItems: 'center',
+ flexDirection: 'row',
+ justifyContent: 'center',
+ opacity: 0.5,
+ },
+ themeToggleButtonContainer: {
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ paddingHorizontal: 20,
+ backgroundColor: '#E0A228',
+ borderRadius: 20,
+ margin: 20
+ },
});
export default Styles;