Initial database structure and migrations, login flow, refactor main page.
This commit is contained in:
@@ -1 +1,3 @@
|
||||
REACT_APP_FIREBASE_CONFIG={"apiKey":"AIzaSyDPLT8GiDHDR1R4nI66Qi0BY1aYviDPioc","authDomain":"imex-dev.firebaseapp.com","databaseURL":"https://imex-dev.firebaseio.com","projectId":"imex-dev","storageBucket":"imex-dev.appspot.com","messagingSenderId":"759548147434","appId":"1:759548147434:web:e8239868a48ceb36700993","measurementId":"G-K5XRBVVB4S"}
|
||||
REACT_APP_FIREBASE_CONFIG={ "apiKey": "AIzaSyCXg148Ma82Qa7dK-2EL4sE0tJhKVnh1rY", "authDomain": "rps-prod-b53c8.firebaseapp.com", "databaseURL": "https://rps-prod-b53c8.firebaseio.com", "projectId": "rps-prod-b53c8", "storageBucket": "rps-prod-b53c8.appspot.com", "messagingSenderId": "361220226954", "appId": "1:361220226954:web:bf3a38d196e4fd8c921273", "measurementId": "G-W3BHH420EC"}
|
||||
REACT_APP_GRAPHQL_ENDPOINT=https://rps.bodyshop.app/v1/graphql
|
||||
REACT_APP_GRAPHQL_ENDPOINT_WS=wss://rps.bodyshop.app/v1/graphql
|
||||
@@ -1 +1,3 @@
|
||||
REACT_APP_FIREBASE_CONFIG={"apiKey":"AIzaSyDPLT8GiDHDR1R4nI66Qi0BY1aYviDPioc","authDomain":"imex-dev.firebaseapp.com","databaseURL":"https://imex-dev.firebaseio.com","projectId":"imex-dev","storageBucket":"imex-dev.appspot.com","messagingSenderId":"759548147434","appId":"1:759548147434:web:e8239868a48ceb36700993","measurementId":"G-K5XRBVVB4S"}
|
||||
REACT_APP_FIREBASE_CONFIG={ "apiKey": "AIzaSyCXg148Ma82Qa7dK-2EL4sE0tJhKVnh1rY", "authDomain": "rps-prod-b53c8.firebaseapp.com", "databaseURL": "https://rps-prod-b53c8.firebaseio.com", "projectId": "rps-prod-b53c8", "storageBucket": "rps-prod-b53c8.appspot.com", "messagingSenderId": "361220226954", "appId": "1:361220226954:web:bf3a38d196e4fd8c921273", "measurementId": "G-W3BHH420EC"}
|
||||
REACT_APP_GRAPHQL_ENDPOINT=https://rps.bodyshop.app/v1/graphql
|
||||
REACT_APP_GRAPHQL_ENDPOINT_WS=wss://rps.bodyshop.app/v1/graphql
|
||||
5
firebase/.firebaserc
Normal file
5
firebase/.firebaserc
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"projects": {
|
||||
"default": "bodyshop-dev-b1cb6"
|
||||
}
|
||||
}
|
||||
65
firebase/.gitignore
vendored
Normal file
65
firebase/.gitignore
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
firebase-debug.log*
|
||||
|
||||
# Firebase cache
|
||||
.firebase/
|
||||
|
||||
# Firebase config
|
||||
|
||||
# Uncomment this if you'd like others to create their own Firebase project.
|
||||
# For a team working on the same Firebase project(s), it is recommended to leave
|
||||
# it commented so all members can deploy to the same project(s) in .firebaserc.
|
||||
# .firebaserc
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
7
firebase/firebase.json
Normal file
7
firebase/firebase.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"functions": {
|
||||
"predeploy": [
|
||||
"npm --prefix \"$RESOURCE_DIR\" run lint"
|
||||
]
|
||||
}
|
||||
}
|
||||
123
firebase/functions/.eslintrc.jsonx
Normal file
123
firebase/functions/.eslintrc.jsonx
Normal file
@@ -0,0 +1,123 @@
|
||||
// {
|
||||
// "parserOptions": {
|
||||
// // Required for certain syntax usages
|
||||
// "ecmaVersion": 2017
|
||||
// },
|
||||
// "plugins": [
|
||||
// "promise"
|
||||
// ],
|
||||
// "extends": "eslint:recommended",
|
||||
// "rules": {
|
||||
// // Removed rule "disallow the use of console" from recommended eslint rules
|
||||
// "no-console": "off",
|
||||
|
||||
// // Removed rule "disallow multiple spaces in regular expressions" from recommended eslint rules
|
||||
// "no-regex-spaces": "off",
|
||||
|
||||
// // Removed rule "disallow the use of debugger" from recommended eslint rules
|
||||
// "no-debugger": "off",
|
||||
|
||||
// // Removed rule "disallow unused variables" from recommended eslint rules
|
||||
// "no-unused-vars": "off",
|
||||
|
||||
// // Removed rule "disallow mixed spaces and tabs for indentation" from recommended eslint rules
|
||||
// "no-mixed-spaces-and-tabs": "off",
|
||||
|
||||
// // Removed rule "disallow the use of undeclared variables unless mentioned in /*global */ comments" from recommended eslint rules
|
||||
// "no-undef": "off",
|
||||
|
||||
// // Warn against template literal placeholder syntax in regular strings
|
||||
// "no-template-curly-in-string": 1,
|
||||
|
||||
// // Warn if return statements do not either always or never specify values
|
||||
// "consistent-return": 1,
|
||||
|
||||
// // Warn if no return statements in callbacks of array methods
|
||||
// "array-callback-return": 1,
|
||||
|
||||
// // Require the use of === and !==
|
||||
// "eqeqeq": 2,
|
||||
|
||||
// // Disallow the use of alert, confirm, and prompt
|
||||
// "no-alert": 2,
|
||||
|
||||
// // Disallow the use of arguments.caller or arguments.callee
|
||||
// "no-caller": 2,
|
||||
|
||||
// // Disallow null comparisons without type-checking operators
|
||||
// "no-eq-null": 2,
|
||||
|
||||
// // Disallow the use of eval()
|
||||
// "no-eval": 2,
|
||||
|
||||
// // Warn against extending native types
|
||||
// "no-extend-native": 1,
|
||||
|
||||
// // Warn against unnecessary calls to .bind()
|
||||
// "no-extra-bind": 1,
|
||||
|
||||
// // Warn against unnecessary labels
|
||||
// "no-extra-label": 1,
|
||||
|
||||
// // Disallow leading or trailing decimal points in numeric literals
|
||||
// "no-floating-decimal": 2,
|
||||
|
||||
// // Warn against shorthand type conversions
|
||||
// "no-implicit-coercion": 1,
|
||||
|
||||
// // Warn against function declarations and expressions inside loop statements
|
||||
// "no-loop-func": 1,
|
||||
|
||||
// // Disallow new operators with the Function object
|
||||
// "no-new-func": 2,
|
||||
|
||||
// // Warn against new operators with the String, Number, and Boolean objects
|
||||
// "no-new-wrappers": 1,
|
||||
|
||||
// // Disallow throwing literals as exceptions
|
||||
// "no-throw-literal": 2,
|
||||
|
||||
// // Require using Error objects as Promise rejection reasons
|
||||
// "prefer-promise-reject-errors": 2,
|
||||
|
||||
// // Enforce “for” loop update clause moving the counter in the right direction
|
||||
// "for-direction": 2,
|
||||
|
||||
// // Enforce return statements in getters
|
||||
// "getter-return": 2,
|
||||
|
||||
// // Disallow await inside of loops
|
||||
// "no-await-in-loop": 2,
|
||||
|
||||
// // Disallow comparing against -0
|
||||
// "no-compare-neg-zero": 2,
|
||||
|
||||
// // Warn against catch clause parameters from shadowing variables in the outer scope
|
||||
// "no-catch-shadow": 1,
|
||||
|
||||
// // Disallow identifiers from shadowing restricted names
|
||||
// "no-shadow-restricted-names": 2,
|
||||
|
||||
// // Enforce return statements in callbacks of array methods
|
||||
// "callback-return": 2,
|
||||
|
||||
// // Require error handling in callbacks
|
||||
// "handle-callback-err": 2,
|
||||
|
||||
// // Warn against string concatenation with __dirname and __filename
|
||||
// "no-path-concat": 1,
|
||||
|
||||
// // Prefer using arrow functions for callbacks
|
||||
// "prefer-arrow-callback": 1,
|
||||
|
||||
// // Return inside each then() to create readable and reusable Promise chains.
|
||||
// // Forces developers to return console logs and http calls in promises.
|
||||
// "promise/always-return": 2,
|
||||
|
||||
// //Enforces the use of catch() on un-returned promises
|
||||
// "promise/catch-or-return": 2,
|
||||
|
||||
// // Warn against nested then() or catch() statements
|
||||
// "promise/no-nesting": 1
|
||||
// }
|
||||
// }
|
||||
1
firebase/functions/.gitignore
vendored
Normal file
1
firebase/functions/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
node_modules/
|
||||
28
firebase/functions/index.js
Normal file
28
firebase/functions/index.js
Normal file
@@ -0,0 +1,28 @@
|
||||
const functions = require("firebase-functions");
|
||||
const admin = require("firebase-admin");
|
||||
admin.initializeApp(functions.config().firebase);
|
||||
|
||||
// On sign up.
|
||||
exports.processSignUp = functions.auth.user().onCreate((user) => {
|
||||
// Check if user meets role criteria:
|
||||
// Your custom logic here: to decide what roles and other `x-hasura-*` should the user get
|
||||
let customClaims;
|
||||
if (user.email && user.email.indexOf("@thinkimex.com") !== -1) {
|
||||
customClaims = {
|
||||
"https://hasura.io/jwt/claims": {
|
||||
"x-hasura-default-role": "admin",
|
||||
"x-hasura-allowed-roles": ["user", "admin"],
|
||||
"x-hasura-user-id": user.uid,
|
||||
},
|
||||
};
|
||||
} else {
|
||||
customClaims = {
|
||||
"https://hasura.io/jwt/claims": {
|
||||
"x-hasura-default-role": "user",
|
||||
"x-hasura-allowed-roles": ["user"],
|
||||
"x-hasura-user-id": user.uid,
|
||||
},
|
||||
};
|
||||
}
|
||||
return admin.auth().setCustomUserClaims(user.uid, customClaims);
|
||||
});
|
||||
2790
firebase/functions/package-lock.json
generated
Normal file
2790
firebase/functions/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
25
firebase/functions/package.json
Normal file
25
firebase/functions/package.json
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"name": "functions",
|
||||
"description": "Cloud Functions for Firebase",
|
||||
"scripts": {
|
||||
"lint": "eslint .",
|
||||
"serve": "firebase serve --only functions",
|
||||
"shell": "firebase functions:shell",
|
||||
"start": "npm run shell",
|
||||
"deploy": "firebase deploy --only functions",
|
||||
"logs": "firebase functions:log"
|
||||
},
|
||||
"engines": {
|
||||
"node": "10"
|
||||
},
|
||||
"dependencies": {
|
||||
"firebase-admin": "^8.6.0",
|
||||
"firebase-functions": "^3.11.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint": "^5.12.0",
|
||||
"eslint-plugin-promise": "^4.0.1",
|
||||
"firebase-functions-test": "^0.1.6"
|
||||
},
|
||||
"private": true
|
||||
}
|
||||
4
firebase/readme.md
Normal file
4
firebase/readme.md
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
Must set the environment variables using:
|
||||
|
||||
firebase functions:config:set auth.graphql_endpoint="https://bodyshop-dev-db.herokuapp.com/v1/graphql" auth.hasura_secret_admin_key="Dev-BodyShopAppBySnaptSoftware!"
|
||||
1
hasura/config.yaml
Normal file
1
hasura/config.yaml
Normal file
@@ -0,0 +1 @@
|
||||
endpoint: https://rps.bodyshop.app
|
||||
@@ -0,0 +1,5 @@
|
||||
- args:
|
||||
cascade: false
|
||||
read_only: false
|
||||
sql: DROP TABLE "public"."users";
|
||||
type: run_sql
|
||||
@@ -0,0 +1,17 @@
|
||||
- args:
|
||||
cascade: false
|
||||
read_only: false
|
||||
sql: "CREATE TABLE \"public\".\"users\"(\"email\" text NOT NULL, \"authid\" text
|
||||
NOT NULL, \"created_at\" timestamptz NOT NULL DEFAULT now(), \"updated_at\"
|
||||
timestamptz NOT NULL DEFAULT now(), PRIMARY KEY (\"email\") );\nCREATE OR REPLACE
|
||||
FUNCTION \"public\".\"set_current_timestamp_updated_at\"()\nRETURNS TRIGGER
|
||||
AS $$\nDECLARE\n _new record;\nBEGIN\n _new := NEW;\n _new.\"updated_at\"
|
||||
= NOW();\n RETURN _new;\nEND;\n$$ LANGUAGE plpgsql;\nCREATE TRIGGER \"set_public_users_updated_at\"\nBEFORE
|
||||
UPDATE ON \"public\".\"users\"\nFOR EACH ROW\nEXECUTE PROCEDURE \"public\".\"set_current_timestamp_updated_at\"();\nCOMMENT
|
||||
ON TRIGGER \"set_public_users_updated_at\" ON \"public\".\"users\" \nIS 'trigger
|
||||
to set value of column \"updated_at\" to current timestamp on row update';"
|
||||
type: run_sql
|
||||
- args:
|
||||
name: users
|
||||
schema: public
|
||||
type: add_existing_table_or_view
|
||||
@@ -0,0 +1,6 @@
|
||||
- args:
|
||||
role: user
|
||||
table:
|
||||
name: users
|
||||
schema: public
|
||||
type: drop_insert_permission
|
||||
@@ -0,0 +1,16 @@
|
||||
- args:
|
||||
permission:
|
||||
allow_upsert: true
|
||||
backend_only: false
|
||||
check: {}
|
||||
columns:
|
||||
- email
|
||||
- authid
|
||||
- created_at
|
||||
- updated_at
|
||||
set: {}
|
||||
role: user
|
||||
table:
|
||||
name: users
|
||||
schema: public
|
||||
type: create_insert_permission
|
||||
@@ -0,0 +1,6 @@
|
||||
- args:
|
||||
role: user
|
||||
table:
|
||||
name: users
|
||||
schema: public
|
||||
type: drop_select_permission
|
||||
@@ -0,0 +1,19 @@
|
||||
- args:
|
||||
permission:
|
||||
allow_aggregations: false
|
||||
backend_only: false
|
||||
columns:
|
||||
- authid
|
||||
- email
|
||||
- created_at
|
||||
- updated_at
|
||||
computed_fields: []
|
||||
filter:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
limit: null
|
||||
role: user
|
||||
table:
|
||||
name: users
|
||||
schema: public
|
||||
type: create_select_permission
|
||||
@@ -0,0 +1,6 @@
|
||||
- args:
|
||||
role: user
|
||||
table:
|
||||
name: users
|
||||
schema: public
|
||||
type: drop_update_permission
|
||||
@@ -0,0 +1,14 @@
|
||||
- args:
|
||||
permission:
|
||||
backend_only: false
|
||||
columns:
|
||||
- authid
|
||||
filter:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
set: {}
|
||||
role: user
|
||||
table:
|
||||
name: users
|
||||
schema: public
|
||||
type: create_update_permission
|
||||
@@ -0,0 +1,5 @@
|
||||
- args:
|
||||
cascade: false
|
||||
read_only: false
|
||||
sql: DROP TABLE "public"."bodyshops";
|
||||
type: run_sql
|
||||
@@ -0,0 +1,22 @@
|
||||
- args:
|
||||
cascade: false
|
||||
read_only: false
|
||||
sql: CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
||||
type: run_sql
|
||||
- args:
|
||||
cascade: false
|
||||
read_only: false
|
||||
sql: "CREATE TABLE \"public\".\"bodyshops\"(\"id\" uuid NOT NULL DEFAULT gen_random_uuid(),
|
||||
\"created_at\" timestamptz NOT NULL DEFAULT now(), \"updated_at\" timestamptz
|
||||
NOT NULL DEFAULT now(), \"shopname\" text NOT NULL, PRIMARY KEY (\"id\") );\nCREATE
|
||||
OR REPLACE FUNCTION \"public\".\"set_current_timestamp_updated_at\"()\nRETURNS
|
||||
TRIGGER AS $$\nDECLARE\n _new record;\nBEGIN\n _new := NEW;\n _new.\"updated_at\"
|
||||
= NOW();\n RETURN _new;\nEND;\n$$ LANGUAGE plpgsql;\nCREATE TRIGGER \"set_public_bodyshops_updated_at\"\nBEFORE
|
||||
UPDATE ON \"public\".\"bodyshops\"\nFOR EACH ROW\nEXECUTE PROCEDURE \"public\".\"set_current_timestamp_updated_at\"();\nCOMMENT
|
||||
ON TRIGGER \"set_public_bodyshops_updated_at\" ON \"public\".\"bodyshops\" \nIS
|
||||
'trigger to set value of column \"updated_at\" to current timestamp on row update';"
|
||||
type: run_sql
|
||||
- args:
|
||||
name: bodyshops
|
||||
schema: public
|
||||
type: add_existing_table_or_view
|
||||
@@ -0,0 +1,5 @@
|
||||
- args:
|
||||
cascade: false
|
||||
read_only: false
|
||||
sql: DROP TABLE "public"."associations";
|
||||
type: run_sql
|
||||
@@ -0,0 +1,13 @@
|
||||
- args:
|
||||
cascade: false
|
||||
read_only: false
|
||||
sql: CREATE TABLE "public"."associations"("email" text NOT NULL, "bodyshopid"
|
||||
uuid NOT NULL, PRIMARY KEY ("email","bodyshopid") , FOREIGN KEY ("bodyshopid")
|
||||
REFERENCES "public"."bodyshops"("id") ON UPDATE cascade ON DELETE cascade, FOREIGN
|
||||
KEY ("email") REFERENCES "public"."users"("email") ON UPDATE cascade ON DELETE
|
||||
cascade);
|
||||
type: run_sql
|
||||
- args:
|
||||
name: associations
|
||||
schema: public
|
||||
type: add_existing_table_or_view
|
||||
@@ -0,0 +1,24 @@
|
||||
- args:
|
||||
relationship: associations
|
||||
table:
|
||||
name: users
|
||||
schema: public
|
||||
type: drop_relationship
|
||||
- args:
|
||||
relationship: associations
|
||||
table:
|
||||
name: bodyshops
|
||||
schema: public
|
||||
type: drop_relationship
|
||||
- args:
|
||||
relationship: bodyshop
|
||||
table:
|
||||
name: associations
|
||||
schema: public
|
||||
type: drop_relationship
|
||||
- args:
|
||||
relationship: user
|
||||
table:
|
||||
name: associations
|
||||
schema: public
|
||||
type: drop_relationship
|
||||
@@ -0,0 +1,40 @@
|
||||
- args:
|
||||
name: associations
|
||||
table:
|
||||
name: users
|
||||
schema: public
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: email
|
||||
table:
|
||||
name: associations
|
||||
schema: public
|
||||
type: create_array_relationship
|
||||
- args:
|
||||
name: associations
|
||||
table:
|
||||
name: bodyshops
|
||||
schema: public
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: bodyshopid
|
||||
table:
|
||||
name: associations
|
||||
schema: public
|
||||
type: create_array_relationship
|
||||
- args:
|
||||
name: bodyshop
|
||||
table:
|
||||
name: associations
|
||||
schema: public
|
||||
using:
|
||||
foreign_key_constraint_on: bodyshopid
|
||||
type: create_object_relationship
|
||||
- args:
|
||||
name: user
|
||||
table:
|
||||
name: associations
|
||||
schema: public
|
||||
using:
|
||||
foreign_key_constraint_on: email
|
||||
type: create_object_relationship
|
||||
@@ -0,0 +1,6 @@
|
||||
- args:
|
||||
role: user
|
||||
table:
|
||||
name: associations
|
||||
schema: public
|
||||
type: drop_select_permission
|
||||
@@ -0,0 +1,18 @@
|
||||
- args:
|
||||
permission:
|
||||
allow_aggregations: false
|
||||
backend_only: false
|
||||
columns:
|
||||
- email
|
||||
- bodyshopid
|
||||
computed_fields: []
|
||||
filter:
|
||||
user:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
limit: null
|
||||
role: user
|
||||
table:
|
||||
name: associations
|
||||
schema: public
|
||||
type: create_select_permission
|
||||
@@ -0,0 +1,6 @@
|
||||
- args:
|
||||
role: user
|
||||
table:
|
||||
name: bodyshops
|
||||
schema: public
|
||||
type: drop_select_permission
|
||||
@@ -0,0 +1,21 @@
|
||||
- args:
|
||||
permission:
|
||||
allow_aggregations: false
|
||||
backend_only: false
|
||||
columns:
|
||||
- id
|
||||
- created_at
|
||||
- updated_at
|
||||
- shopname
|
||||
computed_fields: []
|
||||
filter:
|
||||
associations:
|
||||
user:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
limit: null
|
||||
role: user
|
||||
table:
|
||||
name: bodyshops
|
||||
schema: public
|
||||
type: create_select_permission
|
||||
@@ -0,0 +1,5 @@
|
||||
- args:
|
||||
cascade: false
|
||||
read_only: false
|
||||
sql: DROP TABLE "public"."jobs";
|
||||
type: run_sql
|
||||
@@ -0,0 +1,26 @@
|
||||
- args:
|
||||
cascade: false
|
||||
read_only: false
|
||||
sql: CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
||||
type: run_sql
|
||||
- args:
|
||||
cascade: false
|
||||
read_only: false
|
||||
sql: "CREATE TABLE \"public\".\"jobs\"(\"id\" uuid NOT NULL DEFAULT gen_random_uuid(),
|
||||
\"bodyshopid\" uuid NOT NULL, \"created_at\" timestamptz NOT NULL DEFAULT now(),
|
||||
\"updated_at\" timestamptz NOT NULL DEFAULT now(), \"ro_number\" text, \"ins_co_nm\"
|
||||
text, \"clm_no\" text, \"clm_total\" numeric, \"ownr_ln\" text, \"ownr_fn\"
|
||||
text, \"v_vin\" text, \"v_make_desc\" text, \"v_model_desc\" text, \"v_model_yr\"
|
||||
text, \"v_type\" text, PRIMARY KEY (\"id\") , FOREIGN KEY (\"bodyshopid\") REFERENCES
|
||||
\"public\".\"bodyshops\"(\"id\") ON UPDATE cascade ON DELETE cascade);\nCREATE
|
||||
OR REPLACE FUNCTION \"public\".\"set_current_timestamp_updated_at\"()\nRETURNS
|
||||
TRIGGER AS $$\nDECLARE\n _new record;\nBEGIN\n _new := NEW;\n _new.\"updated_at\"
|
||||
= NOW();\n RETURN _new;\nEND;\n$$ LANGUAGE plpgsql;\nCREATE TRIGGER \"set_public_jobs_updated_at\"\nBEFORE
|
||||
UPDATE ON \"public\".\"jobs\"\nFOR EACH ROW\nEXECUTE PROCEDURE \"public\".\"set_current_timestamp_updated_at\"();\nCOMMENT
|
||||
ON TRIGGER \"set_public_jobs_updated_at\" ON \"public\".\"jobs\" \nIS 'trigger
|
||||
to set value of column \"updated_at\" to current timestamp on row update';"
|
||||
type: run_sql
|
||||
- args:
|
||||
name: jobs
|
||||
schema: public
|
||||
type: add_existing_table_or_view
|
||||
@@ -0,0 +1,12 @@
|
||||
- args:
|
||||
relationship: jobs
|
||||
table:
|
||||
name: bodyshops
|
||||
schema: public
|
||||
type: drop_relationship
|
||||
- args:
|
||||
relationship: bodyshop
|
||||
table:
|
||||
name: jobs
|
||||
schema: public
|
||||
type: drop_relationship
|
||||
@@ -0,0 +1,20 @@
|
||||
- args:
|
||||
name: jobs
|
||||
table:
|
||||
name: bodyshops
|
||||
schema: public
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: bodyshopid
|
||||
table:
|
||||
name: jobs
|
||||
schema: public
|
||||
type: create_array_relationship
|
||||
- args:
|
||||
name: bodyshop
|
||||
table:
|
||||
name: jobs
|
||||
schema: public
|
||||
using:
|
||||
foreign_key_constraint_on: bodyshopid
|
||||
type: create_object_relationship
|
||||
@@ -0,0 +1,6 @@
|
||||
- args:
|
||||
role: user
|
||||
table:
|
||||
name: jobs
|
||||
schema: public
|
||||
type: drop_insert_permission
|
||||
@@ -0,0 +1,32 @@
|
||||
- args:
|
||||
permission:
|
||||
allow_upsert: true
|
||||
backend_only: false
|
||||
check:
|
||||
bodyshop:
|
||||
associations:
|
||||
user:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
columns:
|
||||
- id
|
||||
- bodyshopid
|
||||
- created_at
|
||||
- updated_at
|
||||
- ro_number
|
||||
- ins_co_nm
|
||||
- clm_no
|
||||
- clm_total
|
||||
- ownr_ln
|
||||
- ownr_fn
|
||||
- v_vin
|
||||
- v_make_desc
|
||||
- v_model_desc
|
||||
- v_model_yr
|
||||
- v_type
|
||||
set: {}
|
||||
role: user
|
||||
table:
|
||||
name: jobs
|
||||
schema: public
|
||||
type: create_insert_permission
|
||||
@@ -0,0 +1,6 @@
|
||||
- args:
|
||||
role: user
|
||||
table:
|
||||
name: jobs
|
||||
schema: public
|
||||
type: drop_select_permission
|
||||
@@ -0,0 +1,33 @@
|
||||
- args:
|
||||
permission:
|
||||
allow_aggregations: false
|
||||
backend_only: false
|
||||
columns:
|
||||
- clm_total
|
||||
- clm_no
|
||||
- ins_co_nm
|
||||
- ownr_fn
|
||||
- ownr_ln
|
||||
- ro_number
|
||||
- v_make_desc
|
||||
- v_model_desc
|
||||
- v_model_yr
|
||||
- v_type
|
||||
- v_vin
|
||||
- created_at
|
||||
- updated_at
|
||||
- bodyshopid
|
||||
- id
|
||||
computed_fields: []
|
||||
filter:
|
||||
bodyshop:
|
||||
associations:
|
||||
user:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
limit: null
|
||||
role: user
|
||||
table:
|
||||
name: jobs
|
||||
schema: public
|
||||
type: create_select_permission
|
||||
@@ -0,0 +1,6 @@
|
||||
- args:
|
||||
role: user
|
||||
table:
|
||||
name: jobs
|
||||
schema: public
|
||||
type: drop_update_permission
|
||||
@@ -0,0 +1,31 @@
|
||||
- args:
|
||||
permission:
|
||||
backend_only: false
|
||||
columns:
|
||||
- clm_total
|
||||
- clm_no
|
||||
- ins_co_nm
|
||||
- ownr_fn
|
||||
- ownr_ln
|
||||
- ro_number
|
||||
- v_make_desc
|
||||
- v_model_desc
|
||||
- v_model_yr
|
||||
- v_type
|
||||
- v_vin
|
||||
- created_at
|
||||
- updated_at
|
||||
- bodyshopid
|
||||
- id
|
||||
filter:
|
||||
bodyshop:
|
||||
associations:
|
||||
user:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
set: {}
|
||||
role: user
|
||||
table:
|
||||
name: jobs
|
||||
schema: public
|
||||
type: create_update_permission
|
||||
@@ -0,0 +1,5 @@
|
||||
- args:
|
||||
cascade: false
|
||||
read_only: false
|
||||
sql: DROP TABLE "public"."joblines";
|
||||
type: run_sql
|
||||
@@ -0,0 +1,25 @@
|
||||
- args:
|
||||
cascade: false
|
||||
read_only: false
|
||||
sql: CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
||||
type: run_sql
|
||||
- args:
|
||||
cascade: false
|
||||
read_only: false
|
||||
sql: "CREATE TABLE \"public\".\"joblines\"(\"id\" uuid NOT NULL DEFAULT gen_random_uuid(),
|
||||
\"created_at\" timestamptz NOT NULL DEFAULT now(), \"updated_at\" timestamptz
|
||||
NOT NULL DEFAULT now(), \"jobid\" uuid NOT NULL, \"unq_seq\" text, \"line_ind\"
|
||||
text, \"line_desc\" text, \"part_type\" text, \"oem_partno\" text, \"db_price\"
|
||||
numeric, \"act_price\" numeric, \"part_qty\" numeric, PRIMARY KEY (\"id\") ,
|
||||
FOREIGN KEY (\"jobid\") REFERENCES \"public\".\"jobs\"(\"id\") ON UPDATE cascade
|
||||
ON DELETE cascade);\nCREATE OR REPLACE FUNCTION \"public\".\"set_current_timestamp_updated_at\"()\nRETURNS
|
||||
TRIGGER AS $$\nDECLARE\n _new record;\nBEGIN\n _new := NEW;\n _new.\"updated_at\"
|
||||
= NOW();\n RETURN _new;\nEND;\n$$ LANGUAGE plpgsql;\nCREATE TRIGGER \"set_public_joblines_updated_at\"\nBEFORE
|
||||
UPDATE ON \"public\".\"joblines\"\nFOR EACH ROW\nEXECUTE PROCEDURE \"public\".\"set_current_timestamp_updated_at\"();\nCOMMENT
|
||||
ON TRIGGER \"set_public_joblines_updated_at\" ON \"public\".\"joblines\" \nIS
|
||||
'trigger to set value of column \"updated_at\" to current timestamp on row update';"
|
||||
type: run_sql
|
||||
- args:
|
||||
name: joblines
|
||||
schema: public
|
||||
type: add_existing_table_or_view
|
||||
@@ -0,0 +1,12 @@
|
||||
- args:
|
||||
relationship: joblines
|
||||
table:
|
||||
name: jobs
|
||||
schema: public
|
||||
type: drop_relationship
|
||||
- args:
|
||||
relationship: job
|
||||
table:
|
||||
name: joblines
|
||||
schema: public
|
||||
type: drop_relationship
|
||||
@@ -0,0 +1,20 @@
|
||||
- args:
|
||||
name: joblines
|
||||
table:
|
||||
name: jobs
|
||||
schema: public
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: jobid
|
||||
table:
|
||||
name: joblines
|
||||
schema: public
|
||||
type: create_array_relationship
|
||||
- args:
|
||||
name: job
|
||||
table:
|
||||
name: joblines
|
||||
schema: public
|
||||
using:
|
||||
foreign_key_constraint_on: jobid
|
||||
type: create_object_relationship
|
||||
@@ -0,0 +1,6 @@
|
||||
- args:
|
||||
role: user
|
||||
table:
|
||||
name: joblines
|
||||
schema: public
|
||||
type: drop_insert_permission
|
||||
@@ -0,0 +1,30 @@
|
||||
- args:
|
||||
permission:
|
||||
allow_upsert: true
|
||||
backend_only: false
|
||||
check:
|
||||
job:
|
||||
bodyshop:
|
||||
associations:
|
||||
user:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
columns:
|
||||
- act_price
|
||||
- db_price
|
||||
- part_qty
|
||||
- line_desc
|
||||
- line_ind
|
||||
- oem_partno
|
||||
- part_type
|
||||
- unq_seq
|
||||
- created_at
|
||||
- updated_at
|
||||
- id
|
||||
- jobid
|
||||
set: {}
|
||||
role: user
|
||||
table:
|
||||
name: joblines
|
||||
schema: public
|
||||
type: create_insert_permission
|
||||
@@ -0,0 +1,6 @@
|
||||
- args:
|
||||
role: user
|
||||
table:
|
||||
name: joblines
|
||||
schema: public
|
||||
type: drop_select_permission
|
||||
@@ -0,0 +1,31 @@
|
||||
- args:
|
||||
permission:
|
||||
allow_aggregations: false
|
||||
backend_only: false
|
||||
columns:
|
||||
- act_price
|
||||
- db_price
|
||||
- part_qty
|
||||
- line_desc
|
||||
- line_ind
|
||||
- oem_partno
|
||||
- part_type
|
||||
- unq_seq
|
||||
- created_at
|
||||
- updated_at
|
||||
- id
|
||||
- jobid
|
||||
computed_fields: []
|
||||
filter:
|
||||
job:
|
||||
bodyshop:
|
||||
associations:
|
||||
user:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
limit: null
|
||||
role: user
|
||||
table:
|
||||
name: joblines
|
||||
schema: public
|
||||
type: create_select_permission
|
||||
@@ -0,0 +1,6 @@
|
||||
- args:
|
||||
role: user
|
||||
table:
|
||||
name: joblines
|
||||
schema: public
|
||||
type: drop_update_permission
|
||||
@@ -0,0 +1,29 @@
|
||||
- args:
|
||||
permission:
|
||||
backend_only: false
|
||||
columns:
|
||||
- act_price
|
||||
- db_price
|
||||
- part_qty
|
||||
- line_desc
|
||||
- line_ind
|
||||
- oem_partno
|
||||
- part_type
|
||||
- unq_seq
|
||||
- created_at
|
||||
- updated_at
|
||||
- id
|
||||
- jobid
|
||||
filter:
|
||||
job:
|
||||
bodyshop:
|
||||
associations:
|
||||
user:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
set: {}
|
||||
role: user
|
||||
table:
|
||||
name: joblines
|
||||
schema: public
|
||||
type: create_update_permission
|
||||
264
hasura/migrations/metadata.yaml
Normal file
264
hasura/migrations/metadata.yaml
Normal file
@@ -0,0 +1,264 @@
|
||||
version: 2
|
||||
tables:
|
||||
- table:
|
||||
schema: public
|
||||
name: associations
|
||||
object_relationships:
|
||||
- name: bodyshop
|
||||
using:
|
||||
foreign_key_constraint_on: bodyshopid
|
||||
- name: user
|
||||
using:
|
||||
foreign_key_constraint_on: email
|
||||
select_permissions:
|
||||
- role: user
|
||||
permission:
|
||||
columns:
|
||||
- email
|
||||
- bodyshopid
|
||||
filter:
|
||||
user:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
- table:
|
||||
schema: public
|
||||
name: bodyshops
|
||||
array_relationships:
|
||||
- name: associations
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: bodyshopid
|
||||
table:
|
||||
schema: public
|
||||
name: associations
|
||||
- name: jobs
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: bodyshopid
|
||||
table:
|
||||
schema: public
|
||||
name: jobs
|
||||
select_permissions:
|
||||
- role: user
|
||||
permission:
|
||||
columns:
|
||||
- id
|
||||
- created_at
|
||||
- updated_at
|
||||
- shopname
|
||||
filter:
|
||||
associations:
|
||||
user:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
- table:
|
||||
schema: public
|
||||
name: joblines
|
||||
object_relationships:
|
||||
- name: job
|
||||
using:
|
||||
foreign_key_constraint_on: jobid
|
||||
insert_permissions:
|
||||
- role: user
|
||||
permission:
|
||||
check:
|
||||
job:
|
||||
bodyshop:
|
||||
associations:
|
||||
user:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
columns:
|
||||
- act_price
|
||||
- db_price
|
||||
- part_qty
|
||||
- line_desc
|
||||
- line_ind
|
||||
- oem_partno
|
||||
- part_type
|
||||
- unq_seq
|
||||
- created_at
|
||||
- updated_at
|
||||
- id
|
||||
- jobid
|
||||
backend_only: false
|
||||
select_permissions:
|
||||
- role: user
|
||||
permission:
|
||||
columns:
|
||||
- act_price
|
||||
- db_price
|
||||
- part_qty
|
||||
- line_desc
|
||||
- line_ind
|
||||
- oem_partno
|
||||
- part_type
|
||||
- unq_seq
|
||||
- created_at
|
||||
- updated_at
|
||||
- id
|
||||
- jobid
|
||||
filter:
|
||||
job:
|
||||
bodyshop:
|
||||
associations:
|
||||
user:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
update_permissions:
|
||||
- role: user
|
||||
permission:
|
||||
columns:
|
||||
- act_price
|
||||
- db_price
|
||||
- part_qty
|
||||
- line_desc
|
||||
- line_ind
|
||||
- oem_partno
|
||||
- part_type
|
||||
- unq_seq
|
||||
- created_at
|
||||
- updated_at
|
||||
- id
|
||||
- jobid
|
||||
filter:
|
||||
job:
|
||||
bodyshop:
|
||||
associations:
|
||||
user:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
check: null
|
||||
- table:
|
||||
schema: public
|
||||
name: jobs
|
||||
object_relationships:
|
||||
- name: bodyshop
|
||||
using:
|
||||
foreign_key_constraint_on: bodyshopid
|
||||
array_relationships:
|
||||
- name: joblines
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: jobid
|
||||
table:
|
||||
schema: public
|
||||
name: joblines
|
||||
insert_permissions:
|
||||
- role: user
|
||||
permission:
|
||||
check:
|
||||
bodyshop:
|
||||
associations:
|
||||
user:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
columns:
|
||||
- id
|
||||
- bodyshopid
|
||||
- created_at
|
||||
- updated_at
|
||||
- ro_number
|
||||
- ins_co_nm
|
||||
- clm_no
|
||||
- clm_total
|
||||
- ownr_ln
|
||||
- ownr_fn
|
||||
- v_vin
|
||||
- v_make_desc
|
||||
- v_model_desc
|
||||
- v_model_yr
|
||||
- v_type
|
||||
backend_only: false
|
||||
select_permissions:
|
||||
- role: user
|
||||
permission:
|
||||
columns:
|
||||
- clm_total
|
||||
- clm_no
|
||||
- ins_co_nm
|
||||
- ownr_fn
|
||||
- ownr_ln
|
||||
- ro_number
|
||||
- v_make_desc
|
||||
- v_model_desc
|
||||
- v_model_yr
|
||||
- v_type
|
||||
- v_vin
|
||||
- created_at
|
||||
- updated_at
|
||||
- bodyshopid
|
||||
- id
|
||||
filter:
|
||||
bodyshop:
|
||||
associations:
|
||||
user:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
update_permissions:
|
||||
- role: user
|
||||
permission:
|
||||
columns:
|
||||
- clm_total
|
||||
- clm_no
|
||||
- ins_co_nm
|
||||
- ownr_fn
|
||||
- ownr_ln
|
||||
- ro_number
|
||||
- v_make_desc
|
||||
- v_model_desc
|
||||
- v_model_yr
|
||||
- v_type
|
||||
- v_vin
|
||||
- created_at
|
||||
- updated_at
|
||||
- bodyshopid
|
||||
- id
|
||||
filter:
|
||||
bodyshop:
|
||||
associations:
|
||||
user:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
check: null
|
||||
- table:
|
||||
schema: public
|
||||
name: users
|
||||
array_relationships:
|
||||
- name: associations
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: email
|
||||
table:
|
||||
schema: public
|
||||
name: associations
|
||||
insert_permissions:
|
||||
- role: user
|
||||
permission:
|
||||
check: {}
|
||||
columns:
|
||||
- email
|
||||
- authid
|
||||
- created_at
|
||||
- updated_at
|
||||
backend_only: false
|
||||
select_permissions:
|
||||
- role: user
|
||||
permission:
|
||||
columns:
|
||||
- authid
|
||||
- email
|
||||
- created_at
|
||||
- updated_at
|
||||
filter:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
update_permissions:
|
||||
- role: user
|
||||
permission:
|
||||
columns:
|
||||
- authid
|
||||
filter:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
check: null
|
||||
1031
package-lock.json
generated
1031
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -5,14 +5,18 @@
|
||||
"main": "electron/main.js",
|
||||
"homepage": "./",
|
||||
"dependencies": {
|
||||
"@apollo/client": "^3.2.4",
|
||||
"@fingerprintjs/fingerprintjs": "^2.1.4",
|
||||
"antd": "^4.7.0",
|
||||
"apollo-link-logger": "^2.0.0",
|
||||
"chokidar": "^3.4.3",
|
||||
"dbffile": "^1.4.3",
|
||||
"dotenv": "^8.2.0",
|
||||
"electron-is-dev": "^1.2.0",
|
||||
"electron-settings": "^4.0.2",
|
||||
"electron-squirrel-startup": "^1.0.0",
|
||||
"firebase": "^7.23.0",
|
||||
"graphql": "^15.3.0",
|
||||
"node-sass": "^4.14.1",
|
||||
"react": "^16.13.1",
|
||||
"react-dom": "^16.13.1",
|
||||
@@ -23,7 +27,7 @@
|
||||
"redux-persist": "^6.0.0",
|
||||
"redux-saga": "^1.1.3",
|
||||
"reselect": "^4.0.0",
|
||||
"socket.io-client": "^2.3.1"
|
||||
"subscriptions-transport-ws": "^0.9.18"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
|
||||
@@ -1,55 +1,41 @@
|
||||
import { Button, Layout } from "antd";
|
||||
import { ApolloProvider } from "@apollo/client";
|
||||
import { ConfigProvider, Spin } from "antd";
|
||||
import enLocale from "antd/es/locale/en_US";
|
||||
import React, { useEffect } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import ipcTypes from "../ipc.types";
|
||||
import RoutesPage from "../components/pages/routes/routes.page";
|
||||
import SignInPage from "../components/pages/sign-in/sign-in.page";
|
||||
import client from "../graphql/GraphQLClient";
|
||||
import { checkUserSession } from "../redux/user/user.actions";
|
||||
import { selectCurrentUser } from "../redux/user/user.selectors";
|
||||
|
||||
const { ipcRenderer } = window.require("electron");
|
||||
const settings = window.require("electron-settings");
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
currentUser: selectCurrentUser,
|
||||
});
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
checkUserSession: () => dispatch(checkUserSession()),
|
||||
});
|
||||
|
||||
const mapStateToProps = createStructuredSelector({});
|
||||
const mapDispatchToProps = (dispatch) => ({});
|
||||
|
||||
export function App() {
|
||||
export function App({ currentUser, checkUserSession }) {
|
||||
useEffect(() => {
|
||||
ipcRenderer.on("test-success", (event, obj) => {
|
||||
console.log("Test Success", obj);
|
||||
});
|
||||
ipcRenderer.on(ipcTypes.default.filewatcher.startSuccess, (event, obj) => {
|
||||
console.log(ipcTypes.default.filewatcher.startSuccess, obj);
|
||||
});
|
||||
// Cleanup the listener events so that memory leaks are avoided.
|
||||
return function cleanup() {
|
||||
ipcRenderer.removeAllListeners(
|
||||
"test-success",
|
||||
ipcTypes.default.filewatcher.startSuccess
|
||||
);
|
||||
};
|
||||
}, []);
|
||||
checkUserSession();
|
||||
}, [checkUserSession]);
|
||||
|
||||
if (currentUser.authorized === null) {
|
||||
return <Spin />;
|
||||
}
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
<Layout.Header>
|
||||
<div> Header</div>
|
||||
</Layout.Header>
|
||||
<Layout.Content>
|
||||
<div>Welcome to your new react app. asdas sd</div>
|
||||
<Button
|
||||
onClick={() => {
|
||||
ipcRenderer.send("test", { test: true });
|
||||
}}
|
||||
>
|
||||
TEST Generic IPC
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
ipcRenderer.send(ipcTypes.default.filewatcher.start);
|
||||
}}
|
||||
>
|
||||
Start Watcher
|
||||
</Button>
|
||||
</Layout.Content>
|
||||
</Layout>
|
||||
<ApolloProvider client={client}>
|
||||
<ConfigProvider
|
||||
componentSize="small"
|
||||
input={{ autoComplete: "new-password" }}
|
||||
locale={enLocale}
|
||||
>
|
||||
<div>{currentUser.authorized ? <RoutesPage /> : <SignInPage />}</div>
|
||||
</ConfigProvider>
|
||||
</ApolloProvider>
|
||||
);
|
||||
}
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(App);
|
||||
|
||||
BIN
src/assets/ImEX Logo.png
Normal file
BIN
src/assets/ImEX Logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
BIN
src/assets/logo1024.png
Normal file
BIN
src/assets/logo1024.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 86 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 8.4 KiB After Width: | Height: | Size: 8.7 KiB |
BIN
src/assets/logo512.png
Normal file
BIN
src/assets/logo512.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 27 KiB |
@@ -0,0 +1,17 @@
|
||||
import { Menu } from "antd";
|
||||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { signOutStart } from "../../../redux/user/user.actions";
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
signOutStart: () => dispatch(signOutStart()),
|
||||
});
|
||||
|
||||
export function SiderSignOut({ signOutStart, ...restProps }) {
|
||||
return (
|
||||
<Menu.Item {...restProps} onClick={() => signOutStart()}>
|
||||
Sign Out
|
||||
</Menu.Item>
|
||||
);
|
||||
}
|
||||
export default connect(null, mapDispatchToProps)(SiderSignOut);
|
||||
37
src/components/organisms/sider-menu/sider-menu.organism.jsx
Normal file
37
src/components/organisms/sider-menu/sider-menu.organism.jsx
Normal file
@@ -0,0 +1,37 @@
|
||||
import {
|
||||
DesktopOutlined,
|
||||
FileOutlined,
|
||||
PieChartOutlined,
|
||||
TeamOutlined,
|
||||
UserOutlined,
|
||||
} from "@ant-design/icons";
|
||||
import { Menu } from "antd";
|
||||
import React from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import SiderSignOut from "../../molecules/sider-sign-out/sider-sign-out.molecule";
|
||||
|
||||
const { SubMenu } = Menu;
|
||||
|
||||
export default function SiderMenuOrganism() {
|
||||
return (
|
||||
<Menu defaultSelectedKeys={["1"]} mode="inline">
|
||||
<Menu.Item key="1" icon={<PieChartOutlined />}>
|
||||
<Link to="/">Jobs</Link>
|
||||
</Menu.Item>
|
||||
<Menu.Item key="2" icon={<DesktopOutlined />}>
|
||||
<Link to="/nope">Jobs Not Working</Link>
|
||||
</Menu.Item>
|
||||
<SubMenu key="sub1" icon={<UserOutlined />} title="User">
|
||||
<Menu.Item key="3">Tom</Menu.Item>
|
||||
<Menu.Item key="4">Bill</Menu.Item>
|
||||
<Menu.Item key="5">Alex</Menu.Item>
|
||||
</SubMenu>
|
||||
<SubMenu key="sub2" icon={<TeamOutlined />} title="Team">
|
||||
<Menu.Item key="6">Team 1</Menu.Item>
|
||||
<Menu.Item key="8">Team 2</Menu.Item>
|
||||
</SubMenu>
|
||||
<Menu.Item key="9" icon={<FileOutlined />} />
|
||||
<SiderSignOut />
|
||||
</Menu>
|
||||
);
|
||||
}
|
||||
50
src/components/pages/jobs/jobs.page.jsx
Normal file
50
src/components/pages/jobs/jobs.page.jsx
Normal file
@@ -0,0 +1,50 @@
|
||||
import { Button } from "antd";
|
||||
import React, { useEffect } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import ipcTypes from "../../../ipc.types";
|
||||
|
||||
const { ipcRenderer } = window.require("electron");
|
||||
//const settings = window.require("electron-settings");
|
||||
|
||||
const mapStateToProps = createStructuredSelector({});
|
||||
const mapDispatchToProps = (dispatch) => ({});
|
||||
|
||||
export function JobsPage() {
|
||||
useEffect(() => {
|
||||
ipcRenderer.on("test-success", (event, obj) => {
|
||||
console.log("Test Success", obj);
|
||||
});
|
||||
ipcRenderer.on(ipcTypes.default.filewatcher.startSuccess, (event, obj) => {
|
||||
console.log(ipcTypes.default.filewatcher.startSuccess, obj);
|
||||
});
|
||||
// Cleanup the listener events so that memory leaks are avoided.
|
||||
return function cleanup() {
|
||||
ipcRenderer.removeAllListeners(
|
||||
"test-success",
|
||||
ipcTypes.default.filewatcher.startSuccess
|
||||
);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div>Welcome to your new react app. asdas sd</div>
|
||||
<Button
|
||||
onClick={() => {
|
||||
ipcRenderer.send("test", { test: true });
|
||||
}}
|
||||
>
|
||||
TEST Generic IPC
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
ipcRenderer.send(ipcTypes.default.filewatcher.start);
|
||||
}}
|
||||
>
|
||||
Start Watcher
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(JobsPage);
|
||||
28
src/components/pages/routes/routes.page.jsx
Normal file
28
src/components/pages/routes/routes.page.jsx
Normal file
@@ -0,0 +1,28 @@
|
||||
import { Layout } from "antd";
|
||||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { Route, Switch } from "react-router-dom";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import SiderMenuOrganism from "../../organisms/sider-menu/sider-menu.organism";
|
||||
import Jobs from "../jobs/jobs.page";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({});
|
||||
const mapDispatchToProps = (dispatch) => ({});
|
||||
|
||||
export function RoutesPage() {
|
||||
return (
|
||||
<Layout style={{ background: "#fff" }} hasSider>
|
||||
<Layout.Sider style={{ background: "#fff" }} collapsible>
|
||||
<SiderMenuOrganism />
|
||||
</Layout.Sider>
|
||||
<Layout style={{ background: "#fff" }}>
|
||||
<Layout.Content style={{ margin: "1rem" }}>
|
||||
<Switch>
|
||||
<Route exact path="/" component={Jobs} />
|
||||
</Switch>
|
||||
</Layout.Content>
|
||||
</Layout>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(RoutesPage);
|
||||
59
src/components/pages/sign-in/sign-in.page.jsx
Normal file
59
src/components/pages/sign-in/sign-in.page.jsx
Normal file
@@ -0,0 +1,59 @@
|
||||
import { LockOutlined, UserOutlined } from "@ant-design/icons";
|
||||
import { Alert, Button, Form, Input, Typography } from "antd";
|
||||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { Link } from "react-router-dom";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import ImEXOnlineLogo from "../../../assets/logo192.png";
|
||||
import { emailSignInStart } from "../../../redux/user/user.actions";
|
||||
import { selectSignInError } from "../../../redux/user/user.selectors";
|
||||
import "./sign-in.page.styles.scss";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
signInError: selectSignInError,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
emailSignInStart: (email, password) =>
|
||||
dispatch(emailSignInStart({ email, password })),
|
||||
});
|
||||
|
||||
export function SignInPage({ emailSignInStart, signInError }) {
|
||||
const handleFinish = (values) => {
|
||||
const { email, password } = values;
|
||||
emailSignInStart(email, password);
|
||||
};
|
||||
const [form] = Form.useForm();
|
||||
|
||||
return (
|
||||
<div className="login-container">
|
||||
<div className="login-logo-container">
|
||||
<img src={ImEXOnlineLogo} height="100" width="100" alt="ImEX Online" />
|
||||
<Typography.Title>ImEX RPS</Typography.Title>
|
||||
</div>
|
||||
<Form onFinish={handleFinish} form={form} size="large">
|
||||
<Form.Item name="email" rules={[{ required: true }]}>
|
||||
<Input prefix={<UserOutlined />} placeholder="Email" />
|
||||
</Form.Item>
|
||||
<Form.Item name="password" rules={[{ required: true }]}>
|
||||
<Input
|
||||
prefix={<LockOutlined />}
|
||||
type="password"
|
||||
placeholder="Password"
|
||||
/>
|
||||
</Form.Item>
|
||||
{signInError ? (
|
||||
<Alert type="error" message={signInError.message} />
|
||||
) : null}
|
||||
<Button className="login-btn" type="primary" htmlType="submit">
|
||||
Login
|
||||
</Button>
|
||||
</Form>
|
||||
<Link to={"/resetpassword"}>
|
||||
<Button>Reset Password</Button>
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(SignInPage);
|
||||
29
src/components/pages/sign-in/sign-in.page.styles.scss
Normal file
29
src/components/pages/sign-in/sign-in.page.styles.scss
Normal file
@@ -0,0 +1,29 @@
|
||||
.login-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
padding: 2rem;
|
||||
form {
|
||||
width: 75vw;
|
||||
max-width: 20rem;
|
||||
}
|
||||
}
|
||||
|
||||
.login-logo-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 2rem;
|
||||
h1 {
|
||||
text-align: center;
|
||||
margin: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
//Required as it is position inside form.
|
||||
.login-btn {
|
||||
margin: 1.5rem 0rem;
|
||||
position: relative;
|
||||
left: 50%;
|
||||
transform: translate(-50%, 0);
|
||||
}
|
||||
|
||||
64
src/components/templates/error-boundary.template.jsx
Normal file
64
src/components/templates/error-boundary.template.jsx
Normal file
@@ -0,0 +1,64 @@
|
||||
import { Button, Col, Collapse, Result, Row, Space } from "antd";
|
||||
import React from "react";
|
||||
|
||||
class ErrorBoundary extends React.Component {
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
hasErrored: false,
|
||||
error: null,
|
||||
info: null,
|
||||
};
|
||||
}
|
||||
|
||||
static getDerivedStateFromError(error) {
|
||||
console.log("ErrorBoundary -> getDerivedStateFromError -> error", error);
|
||||
return { hasErrored: true, error: error };
|
||||
}
|
||||
|
||||
componentDidCatch(error, info) {
|
||||
console.log("Exception Caught by Error Boundary.", error, info);
|
||||
this.setState({ ...this.state, error, info });
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.state.hasErrored === true) {
|
||||
return (
|
||||
<div>
|
||||
<Result
|
||||
status="500"
|
||||
title="Error!"
|
||||
subTitle="Error subtitle"
|
||||
extra={
|
||||
<Space>
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={() => {
|
||||
window.location.reload();
|
||||
}}
|
||||
>
|
||||
Refresh
|
||||
</Button>
|
||||
</Space>
|
||||
}
|
||||
/>
|
||||
<Row>
|
||||
<Col offset={6} span={12}>
|
||||
<Collapse bordered={false}>
|
||||
<Collapse.Panel header="Error Details">
|
||||
<div>
|
||||
<strong>{this.state.error.message}</strong>
|
||||
</div>
|
||||
<div>{this.state.error.stack}</div>
|
||||
</Collapse.Panel>
|
||||
</Collapse>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
return this.props.children;
|
||||
}
|
||||
}
|
||||
}
|
||||
export default ErrorBoundary;
|
||||
55
src/components/test.jsx
Normal file
55
src/components/test.jsx
Normal file
@@ -0,0 +1,55 @@
|
||||
import { Button, Layout } from "antd";
|
||||
import React, { useEffect } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import ipcTypes from "../ipc.types";
|
||||
|
||||
const { ipcRenderer } = window.require("electron");
|
||||
//const settings = window.require("electron-settings");
|
||||
|
||||
const mapStateToProps = createStructuredSelector({});
|
||||
const mapDispatchToProps = (dispatch) => ({});
|
||||
|
||||
export function App() {
|
||||
useEffect(() => {
|
||||
ipcRenderer.on("test-success", (event, obj) => {
|
||||
console.log("Test Success", obj);
|
||||
});
|
||||
ipcRenderer.on(ipcTypes.default.filewatcher.startSuccess, (event, obj) => {
|
||||
console.log(ipcTypes.default.filewatcher.startSuccess, obj);
|
||||
});
|
||||
// Cleanup the listener events so that memory leaks are avoided.
|
||||
return function cleanup() {
|
||||
ipcRenderer.removeAllListeners(
|
||||
"test-success",
|
||||
ipcTypes.default.filewatcher.startSuccess
|
||||
);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
<Layout.Header>
|
||||
<div> Header</div>
|
||||
</Layout.Header>
|
||||
<Layout.Content>
|
||||
<div>Welcome to your new react app. asdas sd</div>
|
||||
<Button
|
||||
onClick={() => {
|
||||
ipcRenderer.send("test", { test: true });
|
||||
}}
|
||||
>
|
||||
TEST Generic IPC
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
ipcRenderer.send(ipcTypes.default.filewatcher.start);
|
||||
}}
|
||||
>
|
||||
Start Watcher
|
||||
</Button>
|
||||
</Layout.Content>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(App);
|
||||
@@ -1,18 +1,14 @@
|
||||
import firebase from "firebase/app";
|
||||
import "firebase/firestore";
|
||||
import "firebase/analytics";
|
||||
import "firebase/auth";
|
||||
import "firebase/database";
|
||||
import "firebase/analytics";
|
||||
import "firebase/messaging";
|
||||
import { store } from "../redux/store";
|
||||
import firebase from "firebase/app";
|
||||
|
||||
const config = JSON.parse(process.env.REACT_APP_FIREBASE_CONFIG);
|
||||
firebase.initializeApp(config);
|
||||
|
||||
export const auth = firebase.auth();
|
||||
export const firestore = firebase.firestore();
|
||||
export const analytics = firebase.analytics();
|
||||
|
||||
export default firebase;
|
||||
|
||||
export const getCurrentUser = () => {
|
||||
@@ -34,83 +30,3 @@ export const updateCurrentUser = (userDetails) => {
|
||||
}, reject);
|
||||
});
|
||||
};
|
||||
|
||||
let messaging;
|
||||
try {
|
||||
messaging = firebase.messaging();
|
||||
// Project Settings => Cloud Messaging => Web Push certificates
|
||||
messaging.usePublicVapidKey(process.env.REACT_APP_FIREBASE_PUBLIC_VAPID_KEY);
|
||||
console.log("[FCM UTIL] FCM initialized successfully.");
|
||||
} catch {
|
||||
console.log("[FCM UTIL] Firebase Messaging is likely unsupported.");
|
||||
}
|
||||
|
||||
export { messaging };
|
||||
|
||||
export const logImEXEvent = (eventName, additionalParams, stateProp = null) => {
|
||||
const state = stateProp || store.getState();
|
||||
const eventParams = {
|
||||
shop:
|
||||
(state.user && state.user.bodyshop && state.user.bodyshop.shopname) ||
|
||||
null,
|
||||
user:
|
||||
(state.user && state.user.currentUser && state.user.currentUser.email) ||
|
||||
null,
|
||||
...additionalParams,
|
||||
};
|
||||
analytics.logEvent(eventName, eventParams);
|
||||
};
|
||||
|
||||
if (messaging) {
|
||||
messaging.onMessage(async (payload) => {
|
||||
console.log("[FCM] UTILS Message received. ", payload);
|
||||
navigator.serviceWorker.getRegistration().then((registration) => {
|
||||
return registration.showNotification(
|
||||
"[UTIL]" + payload.notification.title,
|
||||
payload.notification
|
||||
);
|
||||
});
|
||||
|
||||
// if (!payload.clientId) return;
|
||||
|
||||
// // Get the client.
|
||||
// const client = await clients.get(payload.clientId);
|
||||
// // Exit early if we don't get the client.
|
||||
// // Eg, if it closed.
|
||||
// if (!client) return;
|
||||
|
||||
// // Send a message to the client.
|
||||
// console.log("Posting to client.");
|
||||
// client.postMessage({
|
||||
// msg: "Hey I just got a fetch from you!",
|
||||
// url: payload.request.url,
|
||||
// });
|
||||
|
||||
// [START_EXCLUDE]
|
||||
// Update the UI to include the received message.
|
||||
//appendMessage(payload);
|
||||
|
||||
// [END_EXCLUDE]
|
||||
});
|
||||
|
||||
messaging.onTokenRefresh(() => {
|
||||
messaging
|
||||
.getToken()
|
||||
.then((refreshedToken) => {
|
||||
console.log("[FCM] Token refreshed.");
|
||||
// Indicate that the new Instance ID token has not yet been sent to the
|
||||
// app server.
|
||||
// setTokenSentToServer(false);
|
||||
// // Send Instance ID token to app server.
|
||||
// sendTokenToServer(refreshedToken);
|
||||
// // [START_EXCLUDE]
|
||||
// // Display new Instance ID token and clear UI of all previous messages.
|
||||
// resetUI();
|
||||
// [END_EXCLUDE]
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log("[FCM] Unable to retrieve refreshed token ", err);
|
||||
// showToken("Unable to retrieve refreshed token ", err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
130
src/graphql/GraphQLClient.js
Normal file
130
src/graphql/GraphQLClient.js
Normal file
@@ -0,0 +1,130 @@
|
||||
import { ApolloClient, ApolloLink, InMemoryCache } from "@apollo/client";
|
||||
import { setContext } from "@apollo/client/link/context";
|
||||
import { onError } from "@apollo/client/link/error";
|
||||
import { HttpLink } from "@apollo/client/link/http"; //"apollo-link-http";
|
||||
import { RetryLink } from "@apollo/client/link/retry";
|
||||
import { WebSocketLink } from "@apollo/client/link/ws";
|
||||
import { getMainDefinition } from "@apollo/client/utilities";
|
||||
import apolloLogger from "apollo-link-logger";
|
||||
import { auth } from "../firebase/firebase.utils";
|
||||
|
||||
const errorLink = onError(
|
||||
({ graphQLErrors, networkError, operation, forward }) => {
|
||||
if (graphQLErrors)
|
||||
graphQLErrors.forEach(({ message, locations, path }) =>
|
||||
console.log(
|
||||
`[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`
|
||||
)
|
||||
);
|
||||
if (networkError)
|
||||
console.log(`[Network error]: ${JSON.stringify(networkError)}`);
|
||||
console.log(operation.getContext());
|
||||
}
|
||||
);
|
||||
|
||||
const httpLink = new HttpLink({
|
||||
uri: process.env.REACT_APP_GRAPHQL_ENDPOINT,
|
||||
});
|
||||
|
||||
const wsLink = new WebSocketLink({
|
||||
uri: process.env.REACT_APP_GRAPHQL_ENDPOINT_WS,
|
||||
options: {
|
||||
lazy: true,
|
||||
reconnect: true,
|
||||
connectionParams: async () => {
|
||||
const token =
|
||||
auth.currentUser && (await auth.currentUser.getIdToken(true));
|
||||
if (token) {
|
||||
return {
|
||||
headers: {
|
||||
authorization: token ? `Bearer ${token}` : "",
|
||||
},
|
||||
};
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const subscriptionMiddleware = {
|
||||
applyMiddleware: async (options, next) => {
|
||||
options.authToken =
|
||||
auth.currentUser && (await auth.currentUser.getIdToken(true));
|
||||
next();
|
||||
},
|
||||
};
|
||||
wsLink.subscriptionClient.use([subscriptionMiddleware]);
|
||||
|
||||
const link = new HttpLink.split(
|
||||
// split based on operation type
|
||||
({ query }) => {
|
||||
const definition = getMainDefinition(query);
|
||||
// console.log(
|
||||
// "##Intercepted GQL Transaction : " +
|
||||
// definition.operation +
|
||||
// "|" +
|
||||
// definition.name.value +
|
||||
// "##",
|
||||
// query
|
||||
// );
|
||||
return (
|
||||
definition.kind === "OperationDefinition" &&
|
||||
definition.operation === "subscription"
|
||||
);
|
||||
},
|
||||
wsLink,
|
||||
httpLink
|
||||
);
|
||||
|
||||
const authLink = setContext((_, { headers }) => {
|
||||
return (
|
||||
auth.currentUser &&
|
||||
auth.currentUser.getIdToken().then((token) => {
|
||||
if (token) {
|
||||
return {
|
||||
headers: {
|
||||
...headers,
|
||||
authorization: token ? `Bearer ${token}` : "",
|
||||
},
|
||||
};
|
||||
} else {
|
||||
console.log("We have no authorization header.");
|
||||
return { headers };
|
||||
}
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
const retryLink = new RetryLink({
|
||||
delay: {
|
||||
initial: 500,
|
||||
max: 5,
|
||||
jitter: true,
|
||||
},
|
||||
attempts: {
|
||||
max: 5,
|
||||
retryIf: (error, _operation) => !!error,
|
||||
},
|
||||
});
|
||||
|
||||
const middlewares = [];
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
middlewares.push(apolloLogger);
|
||||
}
|
||||
|
||||
middlewares.push(retryLink.concat(errorLink.concat(authLink.concat(link))));
|
||||
|
||||
const cache = new InMemoryCache({});
|
||||
|
||||
export default new ApolloClient({
|
||||
link: ApolloLink.from(middlewares),
|
||||
cache,
|
||||
connectToDevTools: process.env.NODE_ENV !== "production",
|
||||
defaultOptions: {
|
||||
query: {
|
||||
fetchPolicy: "network-only",
|
||||
},
|
||||
watchQuery: {
|
||||
fetchPolicy: "network-only",
|
||||
},
|
||||
},
|
||||
});
|
||||
14
src/graphql/user.queries.js
Normal file
14
src/graphql/user.queries.js
Normal file
@@ -0,0 +1,14 @@
|
||||
import gql from "graphql-tag";
|
||||
|
||||
export const UPSERT_USER = gql`
|
||||
mutation UPSERT_USER($authEmail: String!, $authToken: String!) {
|
||||
insert_users(
|
||||
objects: [{ email: $authEmail, authid: $authToken }]
|
||||
on_conflict: { constraint: users_pkey, update_columns: [authid] }
|
||||
) {
|
||||
returning {
|
||||
authid
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
@@ -1,6 +1,7 @@
|
||||
import { all, call } from "redux-saga/effects";
|
||||
import { applicationSagas } from "./application/application.sagas";
|
||||
import { userSagas } from "./user/user.sagas";
|
||||
|
||||
export default function* rootSaga() {
|
||||
yield all([call(applicationSagas)]);
|
||||
yield all([call(applicationSagas), call(userSagas)]);
|
||||
}
|
||||
|
||||
@@ -1,29 +1,22 @@
|
||||
import Fingerprint2 from "fingerprintjs2";
|
||||
import LogRocket from "logrocket";
|
||||
import { all, call, delay, put, select, takeLatest } from "redux-saga/effects";
|
||||
import { all, call, put, takeLatest } from "redux-saga/effects";
|
||||
import {
|
||||
auth,
|
||||
firestore,
|
||||
getCurrentUser,
|
||||
logImEXEvent,
|
||||
updateCurrentUser,
|
||||
} from "../../firebase/firebase.utils";
|
||||
import client from "../../graphql/GraphQLClient";
|
||||
import { UPSERT_USER } from "../../graphql/user.queries";
|
||||
import {
|
||||
checkInstanceId,
|
||||
setInstanceConflict,
|
||||
setInstanceId,
|
||||
setLocalFingerprint,
|
||||
sendPasswordResetFailure,
|
||||
sendPasswordResetSuccess,
|
||||
signInFailure,
|
||||
signInSuccess,
|
||||
signOutFailure,
|
||||
signOutSuccess,
|
||||
unauthorizedUser,
|
||||
updateUserDetailsSuccess,
|
||||
sendPasswordResetFailure,
|
||||
sendPasswordResetSuccess,
|
||||
validatePasswordResetSuccess,
|
||||
validatePasswordResetFailure,
|
||||
setAuthlevel,
|
||||
validatePasswordResetSuccess,
|
||||
} from "./user.actions";
|
||||
import UserActionTypes from "./user.types";
|
||||
|
||||
@@ -32,9 +25,14 @@ export function* onEmailSignInStart() {
|
||||
}
|
||||
export function* signInWithEmail({ payload: { email, password } }) {
|
||||
try {
|
||||
logImEXEvent("redux_sign_in_attempt", { user: email });
|
||||
|
||||
const { user } = yield auth.signInWithEmailAndPassword(email, password);
|
||||
console.log("function*signInWithEmail -> user", user)
|
||||
|
||||
const result = yield client.mutate({
|
||||
mutation: UPSERT_USER,
|
||||
variables: { authEmail: user.email, authToken: user.uid },
|
||||
});
|
||||
console.log("function*signInWithEmail -> result", result);
|
||||
|
||||
yield put(
|
||||
signInSuccess({
|
||||
@@ -47,7 +45,6 @@ export function* signInWithEmail({ payload: { email, password } }) {
|
||||
);
|
||||
} catch (error) {
|
||||
yield put(signInFailure(error));
|
||||
logImEXEvent("redux_sign_in_failure", { user: email, error });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,15 +53,12 @@ export function* onCheckUserSession() {
|
||||
}
|
||||
export function* isUserAuthenticated() {
|
||||
try {
|
||||
logImEXEvent("redux_auth_check");
|
||||
|
||||
const user = yield getCurrentUser();
|
||||
if (!user) {
|
||||
yield put(unauthorizedUser());
|
||||
return;
|
||||
}
|
||||
|
||||
LogRocket.identify(user.email);
|
||||
yield put(
|
||||
signInSuccess({
|
||||
uid: user.uid,
|
||||
@@ -83,8 +77,6 @@ export function* onSignOutStart() {
|
||||
}
|
||||
export function* signOutStart() {
|
||||
try {
|
||||
logImEXEvent("redux_sign_out");
|
||||
|
||||
yield auth.signOut();
|
||||
yield put(signOutSuccess());
|
||||
localStorage.removeItem("token");
|
||||
@@ -105,66 +97,15 @@ export function* updateUserDetails(userDetails) {
|
||||
//TODO error handling
|
||||
}
|
||||
}
|
||||
export function* onSetInstanceId() {
|
||||
yield takeLatest(UserActionTypes.SET_INSTANCE_ID, setInstanceIdSaga);
|
||||
}
|
||||
export function* setInstanceIdSaga({ payload: uid }) {
|
||||
try {
|
||||
const userInstanceRef = firestore.doc(`userInstance/${uid}`);
|
||||
|
||||
const fingerprint = Fingerprint2.x64hash128(
|
||||
(yield Fingerprint2.getPromise({})).map((c) => c.value).join(""),
|
||||
31
|
||||
);
|
||||
|
||||
yield userInstanceRef.set({
|
||||
timestamp: new Date(),
|
||||
fingerprint,
|
||||
});
|
||||
|
||||
yield put(setLocalFingerprint(fingerprint));
|
||||
yield delay(5 * 60 * 1000);
|
||||
if (process.env.NODE_ENV === "production") yield put(checkInstanceId(uid));
|
||||
} catch (error) {
|
||||
console.log("error", error);
|
||||
//yield put(signOutFailure(error.message));
|
||||
//TODO error handling
|
||||
}
|
||||
}
|
||||
|
||||
export function* onCheckInstanceId() {
|
||||
yield takeLatest(UserActionTypes.CHECK_INSTANCE_ID, checkInstanceIdSaga);
|
||||
}
|
||||
export function* checkInstanceIdSaga({ payload: uid }) {
|
||||
try {
|
||||
const userInstanceRef = firestore.doc(`userInstance/${uid}`);
|
||||
|
||||
const snapshot = yield userInstanceRef.get();
|
||||
let fingerprint = yield select((state) => state.user.fingerprint);
|
||||
|
||||
if (snapshot.data().fingerprint === fingerprint) {
|
||||
yield delay(5 * 60 * 1000);
|
||||
yield put(checkInstanceId(uid));
|
||||
} else {
|
||||
console.log("ERROR: Fingerprints do not match. Conflict detected.");
|
||||
logImEXEvent("instance_confict");
|
||||
yield put(setInstanceConflict());
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("error", error);
|
||||
//TODO error handling
|
||||
}
|
||||
}
|
||||
|
||||
export function* onSignInSuccess() {
|
||||
yield takeLatest(UserActionTypes.SIGN_IN_SUCCESS, signInSuccessSaga);
|
||||
}
|
||||
|
||||
export function* signInSuccessSaga({ payload }) {
|
||||
LogRocket.identify(payload.email);
|
||||
|
||||
if (!payload.email.includes("@imex.")) yield put(setInstanceId(payload.uid));
|
||||
yield logImEXEvent("redux_sign_in_success");
|
||||
// LogRocket.identify(payload.email);
|
||||
// if (!payload.email.includes("@imex.")) yield put(setInstanceId(payload.uid));
|
||||
// yield logImEXEvent("redux_sign_in_success");
|
||||
}
|
||||
|
||||
export function* onSendPasswordResetStart() {
|
||||
@@ -178,7 +119,7 @@ export function* sendPasswordResetEmail({ payload }) {
|
||||
yield auth.sendPasswordResetEmail(payload, {
|
||||
url: "https://imex.online/passwordreset",
|
||||
});
|
||||
console.log("Good should send.");
|
||||
|
||||
yield put(sendPasswordResetSuccess());
|
||||
} catch (error) {
|
||||
yield put(sendPasswordResetFailure(error.message));
|
||||
@@ -201,37 +142,14 @@ export function* validatePasswordResetStart({ payload: { password, code } }) {
|
||||
}
|
||||
}
|
||||
|
||||
export function* onSetShopDetails() {
|
||||
yield takeLatest(
|
||||
UserActionTypes.SET_SHOP_DETAILS,
|
||||
SetAuthLevelFromShopDetails
|
||||
);
|
||||
}
|
||||
export function* SetAuthLevelFromShopDetails({ payload }) {
|
||||
try {
|
||||
const userEmail = yield select((state) => state.user.currentUser.email);
|
||||
|
||||
const authRecord = payload.associations.filter(
|
||||
(a) => a.useremail === userEmail
|
||||
);
|
||||
|
||||
yield put(setAuthlevel(authRecord[0] ? authRecord[0].authlevel : 0));
|
||||
} catch (error) {
|
||||
yield put(signInFailure(error.message));
|
||||
}
|
||||
}
|
||||
|
||||
export function* userSagas() {
|
||||
yield all([
|
||||
call(onEmailSignInStart),
|
||||
call(onCheckUserSession),
|
||||
call(onSignOutStart),
|
||||
call(onUpdateUserDetails),
|
||||
call(onSetInstanceId),
|
||||
call(onCheckInstanceId),
|
||||
call(onSignInSuccess),
|
||||
call(onSendPasswordResetStart),
|
||||
call(onValidatePasswordResetStart),
|
||||
call(onSetShopDetails),
|
||||
]);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user