diff --git a/client/src/App/App.jsx b/client/src/App/App.jsx index a0f02e8cf..ae69a9370 100644 --- a/client/src/App/App.jsx +++ b/client/src/App/App.jsx @@ -21,7 +21,7 @@ import {selectBodyshop, selectCurrentUser,} from "../redux/user/user.selectors"; import PrivateRoute from "../components/PrivateRoute"; import "./App.styles.scss"; import handleBeta from "../utils/betaHandler"; -import Eula, {eulaIsApplicable} from "../components/eula/eula.component"; +import Eula from "../components/eula/eula.component"; const ResetPassword = lazy(() => import("../pages/reset-password/reset-password.component") @@ -45,7 +45,6 @@ const mapDispatchToProps = (dispatch) => ({ export function App({bodyshop, checkUserSession, currentUser, online, setOnline}) { const client = useSplitClient().client; - const [isAccepted, setIsAccepted] = useState(false); const [listenersAdded, setListenersAdded] = useState(false) const {t} = useTranslation(); @@ -125,8 +124,8 @@ export function App({bodyshop, checkUserSession, currentUser, online, setOnline} /> ); - if (eulaIsApplicable({currentUser, isAccepted})) { - return + if (!currentUser.isEulaAccepted) { + return } // Any route that is not assigned and matched will default to the Landing Page component diff --git a/client/src/components/eula/eula.component.jsx b/client/src/components/eula/eula.component.jsx index 6981fbe92..af3bc819e 100644 --- a/client/src/components/eula/eula.component.jsx +++ b/client/src/components/eula/eula.component.jsx @@ -2,142 +2,24 @@ import React, {useState} from "react"; import {Button, Card, Checkbox, Col, Form, Input, Modal, Row, Space} from "antd"; import Markdown from "react-markdown"; -const EULA = `# End User License Agreement (EULA) -## 1. Introduction - -This End User License Agreement ("EULA") governs your use of our website and any related services. By using our website, you agree to be bound by the terms of this EULA. - -## 2. License Grant - -We grant you a non-exclusive, non-transferable, revocable license to use our website for your personal, non-commercial use. - -## 3. Restrictions - -You agree not to: - -- Use our website for any illegal or unauthorized purpose -- Attempt to reverse engineer or otherwise derive the source code of our website - -## 4. Termination - -We reserve the right to terminate your license to use our website at any time and for any reason. - -## 5. Disclaimer of Warranties - -Our website is provided "as is" and without any warranty of any kind. - -## 6. Limitation of Liability - -We will not be liable for any damages or losses arising from your use of our website. - -## 7. Governing Law - -This EULA is governed by the laws of [Your Jurisdiction]. - -## 8. Changes to this EULA - -We reserve the right to modify this EULA at any time. Your continued use of our website after any such changes constitutes your acceptance of the new EULA. - -## 9. Contact Us - -If you have any questions about this EULA, please contact us at [Your Contact Information]. -## 1. Introduction - -This End User License Agreement ("EULA") governs your use of our website and any related services. By using our website, you agree to be bound by the terms of this EULA. - -## 2. License Grant - -We grant you a non-exclusive, non-transferable, revocable license to use our website for your personal, non-commercial use. - -## 3. Restrictions - -You agree not to: - -- Use our website for any illegal or unauthorized purpose -- Attempt to reverse engineer or otherwise derive the source code of our website - -## 4. Termination - -We reserve the right to terminate your license to use our website at any time and for any reason. - -## 5. Disclaimer of Warranties - -Our website is provided "as is" and without any warranty of any kind. - -## 6. Limitation of Liability - -We will not be liable for any damages or losses arising from your use of our website. - -## 7. Governing Law - -This EULA is governed by the laws of [Your Jurisdiction]. - -## 8. Changes to this EULA - -We reserve the right to modify this EULA at any time. Your continued use of our website after any such changes constitutes your acceptance of the new EULA. - -## 9. Contact Us - -If you have any questions about this EULA, please contact us at [Your Contact Information]. -## 1. Introduction - -This End User License Agreement ("EULA") governs your use of our website and any related services. By using our website, you agree to be bound by the terms of this EULA. - -## 2. License Grant - -We grant you a non-exclusive, non-transferable, revocable license to use our website for your personal, non-commercial use. - -## 3. Restrictions - -You agree not to: - -- Use our website for any illegal or unauthorized purpose -- Attempt to reverse engineer or otherwise derive the source code of our website - -## 4. Termination - -We reserve the right to terminate your license to use our website at any time and for any reason. - -## 5. Disclaimer of Warranties - -Our website is provided "as is" and without any warranty of any kind. - -## 6. Limitation of Liability - -We will not be liable for any damages or losses arising from your use of our website. - -## 7. Governing Law - -This EULA is governed by the laws of [Your Jurisdiction]. - -## 8. Changes to this EULA - -We reserve the right to modify this EULA at any time. Your continued use of our website after any such changes constitutes your acceptance of the new EULA. - -## 9. Contact Us - -If you have any questions about this EULA, please contact us at [Your Contact Information].` +const EULA = require('./testData.json').eula; /** - * Returns true if the EULA is applicable to the current user. - * @param currentUser - * @param online - * @param bodyshop - * @param client - * @returns {boolean} + * Returns the EULA component. + * @returns {Element} + * @constructor */ -export function eulaIsApplicable({currentUser, isAccepted}) { - return !isAccepted || currentUser.authorized === false; -} -export default function Eula({setIsAccepted}) { +//REDUXY THIS +export default function Eula({eulaContentToShow}) { const [isModalOpen, setIsModalOpen] = useState(true); const handleAccept = (values) => { localStorage.setItem('termsAccepted', 'true'); - setIsAccepted(true); setIsModalOpen(false); + + //Insert and Dispatch the action to rechecuk force acceptance. }; return ({ type: UserActionTypes.SET_AUTH_LEVEL, payload: authlevel, }); + +export const setEulaContentToShow = (eulaContent) => ({ + type: UserActionTypes.SET_EULA_CONTENT, + payload: eulaContent, +}); + diff --git a/client/src/redux/user/user.reducer.js b/client/src/redux/user/user.reducer.js index f9e391e61..641d127c2 100644 --- a/client/src/redux/user/user.reducer.js +++ b/client/src/redux/user/user.reducer.js @@ -3,6 +3,7 @@ import UserActionTypes from "./user.types"; const INITIAL_STATE = { currentUser: { authorized: null, + eulaIsAccepted: false, //language: "en-US" }, bodyshop: null, @@ -17,6 +18,7 @@ const INITIAL_STATE = { loading: false, }, authLevel: 0, + eulaContentToShow:null }; const userReducer = (state = INITIAL_STATE, action) => { diff --git a/client/src/redux/user/user.sagas.js b/client/src/redux/user/user.sagas.js index 03c217df0..f8837865c 100644 --- a/client/src/redux/user/user.sagas.js +++ b/client/src/redux/user/user.sagas.js @@ -43,6 +43,10 @@ import { validatePasswordResetSuccess, } from "./user.actions"; import UserActionTypes from "./user.types"; +import client from "../../utils/GraphQLClient"; +import {QUERY_SCHEDULE_LOAD_DATA} from "../../graphql/appointments.queries"; +import {QUERY_EULA} from "../../graphql/bodyshop.queries"; +import day from "../../utils/day"; const fpPromise = FingerprintJS.load(); @@ -73,6 +77,8 @@ export function* signInWithEmail({ payload: { email, password } }) { export function* onCheckUserSession() { yield takeLatest(UserActionTypes.CHECK_USER_SESSION, isUserAuthenticated); } + + export function* isUserAuthenticated() { try { logImEXEvent("redux_auth_check"); @@ -85,6 +91,18 @@ export function* isUserAuthenticated() { LogRocket.identify(user.email); + // Get latest eula record and see if they have accepted + // if they have add isEulaAccepted true, if not, take eula text, display it and ask them to accept. + const eulaQuery = yield client.query({ + query: QUERY_EULA, + variables: { + now: day() + }, + }); +console.log("Query Data", eulaQuery) + + const isEulaAccepted = eulaQuery.data.eulas.length > 0 && eulaQuery.data.eulas[0].eula_acceptances.length > 0; + yield put( signInSuccess({ uid: user.uid, @@ -92,6 +110,7 @@ export function* isUserAuthenticated() { displayName: user.displayName, photoURL: user.photoURL, authorized: true, + isEulaAccepted, }) ); } catch (error) { diff --git a/client/src/redux/user/user.selectors.js b/client/src/redux/user/user.selectors.js index ba02c677b..c3d0fe572 100644 --- a/client/src/redux/user/user.selectors.js +++ b/client/src/redux/user/user.selectors.js @@ -36,3 +36,8 @@ export const selectLoginLoading = createSelector( [selectUser], (user) => user.loginLoading ); + +export const selectEulaContentToShow = createSelector( + [selectUser], + (user) => user.eulaContentToShow +); diff --git a/client/src/redux/user/user.types.js b/client/src/redux/user/user.types.js index 7728fcb53..cd4e952cd 100644 --- a/client/src/redux/user/user.types.js +++ b/client/src/redux/user/user.types.js @@ -32,5 +32,6 @@ const UserActionTypes = { CHECK_ACTION_CODE_START: "CHECK_ACTION_CODE_START", CHECK_ACTION_CODE_SUCCESS: "CHECK_ACTION_CODE_SUCCESS", CHECK_ACTION_CODE_FAILURE: "CHECK_ACTION_CODE_FAILURE", + SET_EULA_CONTENT: "SET_EULA_CONTENT" }; export default UserActionTypes; diff --git a/client/src/utils/day.js b/client/src/utils/day.js index b16e16262..0b29aac61 100644 --- a/client/src/utils/day.js +++ b/client/src/utils/day.js @@ -32,11 +32,6 @@ import objectSupport from 'dayjs/plugin/objectSupport'; import toArray from 'dayjs/plugin/toArray'; import toObject from 'dayjs/plugin/toObject'; -// import badMutable from 'dayjs/plugin/badMutable'; -// import preParsePostFormat from 'dayjs/plugin/preParsePostFormat'; - - -// dayjs.extend(badMutable); // TODO: Client Update - This is not advised, scoreboard page dayjs.extend(toObject); dayjs.extend(toArray); dayjs.extend(objectSupport); @@ -46,7 +41,6 @@ dayjs.extend(isToday); dayjs.extend(localeData); dayjs.extend(quarterOfYear); dayjs.extend(localizedFormat); -// dayjs.extend(preParsePostFormat); // TODO: This should not be needed dayjs.extend(isLeapYear); dayjs.extend(isoWeeksInYear); dayjs.extend(isoWeek); diff --git a/hasura/metadata/tables.yaml b/hasura/metadata/tables.yaml index 9867b3f8e..f4e4d99a7 100644 --- a/hasura/metadata/tables.yaml +++ b/hasura/metadata/tables.yaml @@ -2423,6 +2423,73 @@ _eq: X-Hasura-User-Id - active: _eq: true +- table: + name: eula_acceptances + schema: public + object_relationships: + - name: eula + using: + foreign_key_constraint_on: eulaid + - name: user + using: + foreign_key_constraint_on: useremail + insert_permissions: + - role: user + permission: + check: + user: + authid: + _eq: X-Hasura-User-Id + columns: + - address + - buisness_name + - date_accepted + - eulaid + - first_name + - last_name + - phone_number + - useremail + select_permissions: + - role: user + permission: + columns: + - address + - buisness_name + - first_name + - last_name + - phone_number + - useremail + - created_at + - date_accepted + - updated_at + - eulaid + - id + filter: + user: + authid: + _eq: X-Hasura-User-Id +- table: + name: eulas + schema: public + array_relationships: + - name: eula_acceptances + using: + foreign_key_constraint_on: + column: eulaid + table: + name: eula_acceptances + schema: public + select_permissions: + - role: user + permission: + columns: + - id + - created_at + - updated_at + - effective_date + - end_date + - content + filter: {} - table: name: exportlog schema: public @@ -5888,6 +5955,13 @@ table: name: email_audit_trail schema: public + - name: eula_acceptances + using: + foreign_key_constraint_on: + column: useremail + table: + name: eula_acceptances + schema: public - name: exportlogs using: foreign_key_constraint_on: diff --git a/hasura/migrations/1705522419599_create_table_public_eulas/down.sql b/hasura/migrations/1705522419599_create_table_public_eulas/down.sql new file mode 100644 index 000000000..bea9117e2 --- /dev/null +++ b/hasura/migrations/1705522419599_create_table_public_eulas/down.sql @@ -0,0 +1 @@ +DROP TABLE "public"."eulas"; diff --git a/hasura/migrations/1705522419599_create_table_public_eulas/up.sql b/hasura/migrations/1705522419599_create_table_public_eulas/up.sql new file mode 100644 index 000000000..31eaa5f8d --- /dev/null +++ b/hasura/migrations/1705522419599_create_table_public_eulas/up.sql @@ -0,0 +1,18 @@ +CREATE TABLE "public"."eulas" ("id" uuid NOT NULL DEFAULT gen_random_uuid(), "created_at" timestamptz NOT NULL DEFAULT now(), "updated_at" timestamptz NOT NULL DEFAULT now(), "effective_date" timestamptz NOT NULL, "end_date" timestamptz, "content" text NOT NULL, PRIMARY KEY ("id") ); +CREATE OR REPLACE FUNCTION "public"."set_current_timestamp_updated_at"() +RETURNS TRIGGER AS $$ +DECLARE + _new record; +BEGIN + _new := NEW; + _new."updated_at" = NOW(); + RETURN _new; +END; +$$ LANGUAGE plpgsql; +CREATE TRIGGER "set_public_eulas_updated_at" +BEFORE UPDATE ON "public"."eulas" +FOR EACH ROW +EXECUTE PROCEDURE "public"."set_current_timestamp_updated_at"(); +COMMENT ON TRIGGER "set_public_eulas_updated_at" ON "public"."eulas" +IS 'trigger to set value of column "updated_at" to current timestamp on row update'; +CREATE EXTENSION IF NOT EXISTS pgcrypto; diff --git a/hasura/migrations/1705522869369_create_table_public_eula_acceptances/down.sql b/hasura/migrations/1705522869369_create_table_public_eula_acceptances/down.sql new file mode 100644 index 000000000..29d08ee95 --- /dev/null +++ b/hasura/migrations/1705522869369_create_table_public_eula_acceptances/down.sql @@ -0,0 +1 @@ +DROP TABLE "public"."eula_acceptances"; diff --git a/hasura/migrations/1705522869369_create_table_public_eula_acceptances/up.sql b/hasura/migrations/1705522869369_create_table_public_eula_acceptances/up.sql new file mode 100644 index 000000000..18dc09e8e --- /dev/null +++ b/hasura/migrations/1705522869369_create_table_public_eula_acceptances/up.sql @@ -0,0 +1,18 @@ +CREATE TABLE "public"."eula_acceptances" ("id" uuid NOT NULL DEFAULT gen_random_uuid(), "created_at" timestamptz NOT NULL DEFAULT now(), "updated_at" timestamptz NOT NULL DEFAULT now(), "eulaid" uuid NOT NULL, "date_accepted" timestamptz NOT NULL, "first_name" text NOT NULL, "last_name" text NOT NULL, "address" text NOT NULL, "phone_number" Text NOT NULL, "buisness_name" Text NOT NULL, "useremail" text NOT NULL, PRIMARY KEY ("id") , FOREIGN KEY ("eulaid") REFERENCES "public"."eulas"("id") ON UPDATE restrict ON DELETE restrict, FOREIGN KEY ("useremail") REFERENCES "public"."users"("email") ON UPDATE restrict ON DELETE restrict); +CREATE OR REPLACE FUNCTION "public"."set_current_timestamp_updated_at"() +RETURNS TRIGGER AS $$ +DECLARE + _new record; +BEGIN + _new := NEW; + _new."updated_at" = NOW(); + RETURN _new; +END; +$$ LANGUAGE plpgsql; +CREATE TRIGGER "set_public_eula_acceptances_updated_at" +BEFORE UPDATE ON "public"."eula_acceptances" +FOR EACH ROW +EXECUTE PROCEDURE "public"."set_current_timestamp_updated_at"(); +COMMENT ON TRIGGER "set_public_eula_acceptances_updated_at" ON "public"."eula_acceptances" +IS 'trigger to set value of column "updated_at" to current timestamp on row update'; +CREATE EXTENSION IF NOT EXISTS pgcrypto;