@@ -1,69 +1,69 @@
|
||||
import ApplicationActionTypes from "./application.types";
|
||||
|
||||
export const startLoading = () => ({
|
||||
type: ApplicationActionTypes.START_LOADING,
|
||||
type: ApplicationActionTypes.START_LOADING,
|
||||
});
|
||||
|
||||
export const endLoading = (options) => ({
|
||||
type: ApplicationActionTypes.END_LOADING,
|
||||
payload: options,
|
||||
type: ApplicationActionTypes.END_LOADING,
|
||||
payload: options,
|
||||
});
|
||||
|
||||
export const setBreadcrumbs = (breadcrumbs) => ({
|
||||
type: ApplicationActionTypes.SET_BREAD_CRUMBS,
|
||||
payload: breadcrumbs,
|
||||
type: ApplicationActionTypes.SET_BREAD_CRUMBS,
|
||||
payload: breadcrumbs,
|
||||
});
|
||||
|
||||
export const calculateScheduleLoad = (rangeEnd) => ({
|
||||
type: ApplicationActionTypes.CALCULATE_SCHEDULE_LOAD,
|
||||
payload: rangeEnd,
|
||||
type: ApplicationActionTypes.CALCULATE_SCHEDULE_LOAD,
|
||||
payload: rangeEnd,
|
||||
});
|
||||
|
||||
export const scheduleLoadSuccess = (load) => ({
|
||||
type: ApplicationActionTypes.CALCULATE_SCHEDULE_LOAD_SUCCESS,
|
||||
payload: load,
|
||||
type: ApplicationActionTypes.CALCULATE_SCHEDULE_LOAD_SUCCESS,
|
||||
payload: load,
|
||||
});
|
||||
|
||||
export const scheduleLoadFailure = (error) => ({
|
||||
type: ApplicationActionTypes.CALCULATE_SCHEDULE_LOAD_FAILURE,
|
||||
payload: error,
|
||||
type: ApplicationActionTypes.CALCULATE_SCHEDULE_LOAD_FAILURE,
|
||||
payload: error,
|
||||
});
|
||||
|
||||
export const addRecentItem = (item) => ({
|
||||
type: ApplicationActionTypes.ADD_RECENT_ITEM,
|
||||
payload: item,
|
||||
type: ApplicationActionTypes.ADD_RECENT_ITEM,
|
||||
payload: item,
|
||||
});
|
||||
|
||||
export const setSelectedHeader = (key) => ({
|
||||
type: ApplicationActionTypes.SET_SELECTED_HEADER,
|
||||
payload: key,
|
||||
type: ApplicationActionTypes.SET_SELECTED_HEADER,
|
||||
payload: key,
|
||||
});
|
||||
|
||||
export const setJobReadOnly = (bool) => ({
|
||||
type: ApplicationActionTypes.SET_JOB_READONLY,
|
||||
payload: bool,
|
||||
type: ApplicationActionTypes.SET_JOB_READONLY,
|
||||
payload: bool,
|
||||
});
|
||||
|
||||
export const setPartnerVersion = (version) => ({
|
||||
type: ApplicationActionTypes.SET_PARTNER_VERSION,
|
||||
payload: version,
|
||||
type: ApplicationActionTypes.SET_PARTNER_VERSION,
|
||||
payload: version,
|
||||
});
|
||||
|
||||
export const setOnline = (isOnline) => ({
|
||||
type: ApplicationActionTypes.SET_ONLINE_STATUS,
|
||||
payload: isOnline,
|
||||
type: ApplicationActionTypes.SET_ONLINE_STATUS,
|
||||
payload: isOnline,
|
||||
});
|
||||
|
||||
export const insertAuditTrail = ({ jobid, billid, operation }) => ({
|
||||
type: ApplicationActionTypes.INSERT_AUDIT_TRAIL,
|
||||
payload: { jobid, billid, operation },
|
||||
export const insertAuditTrail = ({jobid, billid, operation}) => ({
|
||||
type: ApplicationActionTypes.INSERT_AUDIT_TRAIL,
|
||||
payload: {jobid, billid, operation},
|
||||
});
|
||||
export const setProblemJobs = (problemJobs) => ({
|
||||
type: ApplicationActionTypes.SET_PROBLEM_JOBS,
|
||||
payload: problemJobs,
|
||||
type: ApplicationActionTypes.SET_PROBLEM_JOBS,
|
||||
payload: problemJobs,
|
||||
});
|
||||
|
||||
export const setUpdateAvailable = (isUpdateAvailable) => ({
|
||||
type: ApplicationActionTypes.SET_UPDATE_AVAILABLE,
|
||||
payload: isUpdateAvailable,
|
||||
type: ApplicationActionTypes.SET_UPDATE_AVAILABLE,
|
||||
payload: isUpdateAvailable,
|
||||
});
|
||||
|
||||
@@ -1,110 +1,110 @@
|
||||
import ApplicationActionTypes from "./application.types";
|
||||
|
||||
const INITIAL_STATE = {
|
||||
loading: false,
|
||||
online: true,
|
||||
updateAvailable: false,
|
||||
breadcrumbs: [],
|
||||
recentItems: [],
|
||||
selectedHeader: "home",
|
||||
problemJobs: [],
|
||||
scheduleLoad: {
|
||||
load: {},
|
||||
calculating: false,
|
||||
error: null,
|
||||
},
|
||||
jobReadOnly: false,
|
||||
partnerVersion: null,
|
||||
loading: false,
|
||||
online: true,
|
||||
updateAvailable: false,
|
||||
breadcrumbs: [],
|
||||
recentItems: [],
|
||||
selectedHeader: "home",
|
||||
problemJobs: [],
|
||||
scheduleLoad: {
|
||||
load: {},
|
||||
calculating: false,
|
||||
error: null,
|
||||
},
|
||||
jobReadOnly: false,
|
||||
partnerVersion: null,
|
||||
};
|
||||
|
||||
const applicationReducer = (state = INITIAL_STATE, action) => {
|
||||
switch (action.type) {
|
||||
case ApplicationActionTypes.SET_UPDATE_AVAILABLE:
|
||||
return {
|
||||
...state,
|
||||
updateAvailable: action.payload,
|
||||
};
|
||||
case ApplicationActionTypes.SET_SELECTED_HEADER:
|
||||
return {
|
||||
...state,
|
||||
selectedHeader: action.payload,
|
||||
};
|
||||
case ApplicationActionTypes.SET_ONLINE_STATUS:
|
||||
return {
|
||||
...state,
|
||||
online: action.payload,
|
||||
};
|
||||
case ApplicationActionTypes.ADD_RECENT_ITEM:
|
||||
return {
|
||||
...state,
|
||||
recentItems: updateRecentItemsArray(state, action.payload),
|
||||
};
|
||||
case ApplicationActionTypes.SET_BREAD_CRUMBS:
|
||||
return {
|
||||
...state,
|
||||
breadcrumbs: action.payload,
|
||||
};
|
||||
case ApplicationActionTypes.CALCULATE_SCHEDULE_LOAD:
|
||||
return {
|
||||
...state,
|
||||
problemJobs: [],
|
||||
scheduleLoad: { ...state.scheduleLoad, calculating: true, error: null },
|
||||
};
|
||||
case ApplicationActionTypes.CALCULATE_SCHEDULE_LOAD_SUCCESS:
|
||||
return {
|
||||
...state,
|
||||
scheduleLoad: {
|
||||
...state.scheduleLoad,
|
||||
load: action.payload,
|
||||
calculating: false,
|
||||
},
|
||||
};
|
||||
case ApplicationActionTypes.CALCULATE_SCHEDULE_LOAD_FAILURE:
|
||||
return {
|
||||
...state,
|
||||
scheduleLoad: {
|
||||
...state.scheduleLoad,
|
||||
calculating: false,
|
||||
error: action.payload,
|
||||
},
|
||||
};
|
||||
case ApplicationActionTypes.START_LOADING:
|
||||
return {
|
||||
...state,
|
||||
loading: true,
|
||||
};
|
||||
case ApplicationActionTypes.END_LOADING:
|
||||
return {
|
||||
...state,
|
||||
loading: false,
|
||||
};
|
||||
switch (action.type) {
|
||||
case ApplicationActionTypes.SET_UPDATE_AVAILABLE:
|
||||
return {
|
||||
...state,
|
||||
updateAvailable: action.payload,
|
||||
};
|
||||
case ApplicationActionTypes.SET_SELECTED_HEADER:
|
||||
return {
|
||||
...state,
|
||||
selectedHeader: action.payload,
|
||||
};
|
||||
case ApplicationActionTypes.SET_ONLINE_STATUS:
|
||||
return {
|
||||
...state,
|
||||
online: action.payload,
|
||||
};
|
||||
case ApplicationActionTypes.ADD_RECENT_ITEM:
|
||||
return {
|
||||
...state,
|
||||
recentItems: updateRecentItemsArray(state, action.payload),
|
||||
};
|
||||
case ApplicationActionTypes.SET_BREAD_CRUMBS:
|
||||
return {
|
||||
...state,
|
||||
breadcrumbs: action.payload,
|
||||
};
|
||||
case ApplicationActionTypes.CALCULATE_SCHEDULE_LOAD:
|
||||
return {
|
||||
...state,
|
||||
problemJobs: [],
|
||||
scheduleLoad: {...state.scheduleLoad, calculating: true, error: null},
|
||||
};
|
||||
case ApplicationActionTypes.CALCULATE_SCHEDULE_LOAD_SUCCESS:
|
||||
return {
|
||||
...state,
|
||||
scheduleLoad: {
|
||||
...state.scheduleLoad,
|
||||
load: action.payload,
|
||||
calculating: false,
|
||||
},
|
||||
};
|
||||
case ApplicationActionTypes.CALCULATE_SCHEDULE_LOAD_FAILURE:
|
||||
return {
|
||||
...state,
|
||||
scheduleLoad: {
|
||||
...state.scheduleLoad,
|
||||
calculating: false,
|
||||
error: action.payload,
|
||||
},
|
||||
};
|
||||
case ApplicationActionTypes.START_LOADING:
|
||||
return {
|
||||
...state,
|
||||
loading: true,
|
||||
};
|
||||
case ApplicationActionTypes.END_LOADING:
|
||||
return {
|
||||
...state,
|
||||
loading: false,
|
||||
};
|
||||
|
||||
case ApplicationActionTypes.SET_JOB_READONLY:
|
||||
return { ...state, jobReadOnly: action.payload };
|
||||
case ApplicationActionTypes.SET_JOB_READONLY:
|
||||
return {...state, jobReadOnly: action.payload};
|
||||
|
||||
case ApplicationActionTypes.SET_PARTNER_VERSION:
|
||||
return { ...state, partnerVersion: action.payload };
|
||||
case ApplicationActionTypes.SET_PROBLEM_JOBS: {
|
||||
return { ...state, problemJobs: action.payload };
|
||||
case ApplicationActionTypes.SET_PARTNER_VERSION:
|
||||
return {...state, partnerVersion: action.payload};
|
||||
case ApplicationActionTypes.SET_PROBLEM_JOBS: {
|
||||
return {...state, problemJobs: action.payload};
|
||||
}
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
export default applicationReducer;
|
||||
|
||||
const updateRecentItemsArray = (state, newItem) => {
|
||||
//Check to see if the new item is in the list.
|
||||
const matchingIndex = state.recentItems.findIndex((i) => i.id === newItem.id);
|
||||
//Check to see if the new item is in the list.
|
||||
const matchingIndex = state.recentItems.findIndex((i) => i.id === newItem.id);
|
||||
|
||||
if (matchingIndex >= 0) {
|
||||
return [
|
||||
newItem,
|
||||
...state.recentItems.slice(0, matchingIndex),
|
||||
...state.recentItems.slice(matchingIndex + 1, 9),
|
||||
];
|
||||
} else {
|
||||
return [newItem, ...state.recentItems.slice(0, 9)];
|
||||
}
|
||||
if (matchingIndex >= 0) {
|
||||
return [
|
||||
newItem,
|
||||
...state.recentItems.slice(0, matchingIndex),
|
||||
...state.recentItems.slice(matchingIndex + 1, 9),
|
||||
];
|
||||
} else {
|
||||
return [newItem, ...state.recentItems.slice(0, 9)];
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,306 +1,303 @@
|
||||
import dayjs from "../../utils/day";
|
||||
import { all, call, put, select, takeLatest } from "redux-saga/effects";
|
||||
import { QUERY_SCHEDULE_LOAD_DATA } from "../../graphql/appointments.queries";
|
||||
import { INSERT_AUDIT_TRAIL } from "../../graphql/audit_trail.queries";
|
||||
import {all, call, put, select, takeLatest} from "redux-saga/effects";
|
||||
import {QUERY_SCHEDULE_LOAD_DATA} from "../../graphql/appointments.queries";
|
||||
import {INSERT_AUDIT_TRAIL} from "../../graphql/audit_trail.queries";
|
||||
import client from "../../utils/GraphQLClient";
|
||||
import { CalculateLoad, CheckJobBucket } from "../../utils/SSSUtils";
|
||||
import {
|
||||
scheduleLoadFailure,
|
||||
scheduleLoadSuccess,
|
||||
setProblemJobs,
|
||||
} from "./application.actions";
|
||||
import {CalculateLoad, CheckJobBucket} from "../../utils/SSSUtils";
|
||||
import {scheduleLoadFailure, scheduleLoadSuccess, setProblemJobs,} from "./application.actions";
|
||||
import ApplicationActionTypes from "./application.types";
|
||||
|
||||
export function* onCalculateScheduleLoad() {
|
||||
yield takeLatest(
|
||||
ApplicationActionTypes.CALCULATE_SCHEDULE_LOAD,
|
||||
calculateScheduleLoad
|
||||
);
|
||||
yield takeLatest(
|
||||
ApplicationActionTypes.CALCULATE_SCHEDULE_LOAD,
|
||||
calculateScheduleLoad
|
||||
);
|
||||
}
|
||||
export function* calculateScheduleLoad({ payload: end }) {
|
||||
//REMINDER: dayjs.js is not immutable. Today WILL change when adjusted.
|
||||
const today = dayjs().startOf("day");
|
||||
const state = yield select();
|
||||
const buckets = state.user.bodyshop.ssbuckets;
|
||||
|
||||
try {
|
||||
const result = yield client.query({
|
||||
query: QUERY_SCHEDULE_LOAD_DATA,
|
||||
variables: {
|
||||
start: today,
|
||||
end: end,
|
||||
},
|
||||
});
|
||||
const { prodJobs, arrJobs, compJobs } = result.data;
|
||||
export function* calculateScheduleLoad({payload: end}) {
|
||||
//REMINDER: dayjs.js is not immutable. Today WILL change when adjusted.
|
||||
const today = dayjs().startOf("day");
|
||||
const state = yield select();
|
||||
const buckets = state.user.bodyshop.ssbuckets;
|
||||
|
||||
const load = {
|
||||
productionTotal: {},
|
||||
productionHours: 0,
|
||||
};
|
||||
let problemJobs = [];
|
||||
//Set the current load.
|
||||
buckets.forEach((bucket) => {
|
||||
load.productionTotal[bucket.id] = { count: 0, label: bucket.label };
|
||||
});
|
||||
|
||||
prodJobs.forEach((item) => {
|
||||
//Add all of the jobs currently in production to the buckets so that we have a starting point.
|
||||
if (
|
||||
!item.actual_completion &&
|
||||
dayjs(item.scheduled_completion).isBefore(dayjs().startOf("day"))
|
||||
) {
|
||||
problemJobs.push({
|
||||
...item,
|
||||
code: "Job was scheduled to go, but it has not been completed. Update the scheduled completion date to correct projections",
|
||||
try {
|
||||
const result = yield client.query({
|
||||
query: QUERY_SCHEDULE_LOAD_DATA,
|
||||
variables: {
|
||||
start: today,
|
||||
end: end,
|
||||
},
|
||||
});
|
||||
}
|
||||
const {prodJobs, arrJobs, compJobs} = result.data;
|
||||
|
||||
if (
|
||||
item.actual_completion &&
|
||||
dayjs(item.actual_completion).isBefore(dayjs().startOf("day"))
|
||||
) {
|
||||
problemJobs.push({
|
||||
...item,
|
||||
code: "Job is already marked as completed, but it is still in production. This job should be removed from production",
|
||||
});
|
||||
}
|
||||
if (!(item.actual_completion || item.scheduled_completion)) {
|
||||
problemJobs.push({
|
||||
...item,
|
||||
code: "Job does not have a scheduled or actual completion date. Update the scheduled or actual completion dates to correct projections",
|
||||
});
|
||||
}
|
||||
|
||||
const bucketId = CheckJobBucket(buckets, item);
|
||||
load.productionHours =
|
||||
load.productionHours +
|
||||
item.labhrs.aggregate.sum.mod_lb_hrs +
|
||||
item.larhrs.aggregate.sum.mod_lb_hrs;
|
||||
if (bucketId) {
|
||||
load.productionTotal[bucketId].count =
|
||||
load.productionTotal[bucketId].count + 1;
|
||||
} else {
|
||||
console.log("Uh oh, this job doesn't fit in a bucket!", item);
|
||||
}
|
||||
});
|
||||
|
||||
arrJobs.forEach((item) => {
|
||||
if (!item.scheduled_in) {
|
||||
console.log("JOB HAS NO SCHEDULED IN DATE.", item);
|
||||
problemJobs.push({
|
||||
...item,
|
||||
code: "Job has no scheduled in date",
|
||||
});
|
||||
}
|
||||
if (!item.actual_completion && item.actual_in && !item.inproduction) {
|
||||
problemJobs.push({
|
||||
...item,
|
||||
code: "Job has an actual in date, but no actual completion date and is not marked as in production",
|
||||
});
|
||||
}
|
||||
if (item.actual_in && dayjs(item.actual_in).isAfter(dayjs())) {
|
||||
problemJobs.push({
|
||||
...item,
|
||||
code: "Job has an actual in date set in the future",
|
||||
});
|
||||
}
|
||||
if (
|
||||
item.actual_completion &&
|
||||
dayjs(item.actual_completion).isAfter(dayjs())
|
||||
) {
|
||||
problemJobs.push({
|
||||
...item,
|
||||
code: "Job has an actual completion date set in the future",
|
||||
});
|
||||
}
|
||||
if (item.actual_completion && item.inproduction) {
|
||||
problemJobs.push({
|
||||
...item,
|
||||
code: "Job has an actual completion date but it is still marked in production",
|
||||
});
|
||||
}
|
||||
|
||||
const itemDate = dayjs(item.actual_in || item.scheduled_in).format(
|
||||
"YYYY-MM-DD"
|
||||
);
|
||||
|
||||
const AddJobForSchedulingCalc = !item.inproduction;
|
||||
|
||||
if (!!load[itemDate]) {
|
||||
load[itemDate].allHoursIn =
|
||||
(load[itemDate].allHoursIn || 0) +
|
||||
item.labhrs.aggregate.sum.mod_lb_hrs +
|
||||
item.larhrs.aggregate.sum.mod_lb_hrs;
|
||||
|
||||
//If the job hasn't already arrived, add it to the jobs in list.
|
||||
// Make sure it also hasn't already been completed, or isn't an in and out job.
|
||||
//This prevents the duplicate counting.
|
||||
load[itemDate].allJobsIn.push(item);
|
||||
if (AddJobForSchedulingCalc) {
|
||||
load[itemDate].jobsIn.push(item);
|
||||
load[itemDate].hoursIn =
|
||||
(load[itemDate].hoursIn || 0) +
|
||||
item.labhrs.aggregate.sum.mod_lb_hrs +
|
||||
item.larhrs.aggregate.sum.mod_lb_hrs;
|
||||
}
|
||||
} else {
|
||||
load[itemDate] = {
|
||||
allJobsIn: [item],
|
||||
jobsIn: AddJobForSchedulingCalc ? [item] : [], //Same as above, only add it if it isn't already in production.
|
||||
jobsOut: [],
|
||||
allJobsOut: [],
|
||||
allHoursIn:
|
||||
item.labhrs.aggregate.sum.mod_lb_hrs +
|
||||
item.larhrs.aggregate.sum.mod_lb_hrs,
|
||||
hoursIn: AddJobForSchedulingCalc
|
||||
? item.labhrs.aggregate.sum.mod_lb_hrs +
|
||||
item.larhrs.aggregate.sum.mod_lb_hrs
|
||||
: 0,
|
||||
const load = {
|
||||
productionTotal: {},
|
||||
productionHours: 0,
|
||||
};
|
||||
}
|
||||
});
|
||||
let problemJobs = [];
|
||||
//Set the current load.
|
||||
buckets.forEach((bucket) => {
|
||||
load.productionTotal[bucket.id] = {count: 0, label: bucket.label};
|
||||
});
|
||||
|
||||
compJobs.forEach((item) => {
|
||||
if (!(item.actual_completion || item.scheduled_completion))
|
||||
console.warn("JOB HAS NO COMPLETION DATE.", item);
|
||||
prodJobs.forEach((item) => {
|
||||
//Add all of the jobs currently in production to the buckets so that we have a starting point.
|
||||
if (
|
||||
!item.actual_completion &&
|
||||
dayjs(item.scheduled_completion).isBefore(dayjs().startOf("day"))
|
||||
) {
|
||||
problemJobs.push({
|
||||
...item,
|
||||
code: "Job was scheduled to go, but it has not been completed. Update the scheduled completion date to correct projections",
|
||||
});
|
||||
}
|
||||
|
||||
const inProdJobs = prodJobs.find((p) => p.id === item.id);
|
||||
const inArrJobs = arrJobs.find((p) => p.id === item.id);
|
||||
if (
|
||||
item.actual_completion &&
|
||||
dayjs(item.actual_completion).isBefore(dayjs().startOf("day"))
|
||||
) {
|
||||
problemJobs.push({
|
||||
...item,
|
||||
code: "Job is already marked as completed, but it is still in production. This job should be removed from production",
|
||||
});
|
||||
}
|
||||
if (!(item.actual_completion || item.scheduled_completion)) {
|
||||
problemJobs.push({
|
||||
...item,
|
||||
code: "Job does not have a scheduled or actual completion date. Update the scheduled or actual completion dates to correct projections",
|
||||
});
|
||||
}
|
||||
|
||||
const AddJobForSchedulingCalc = inProdJobs || inArrJobs;
|
||||
const bucketId = CheckJobBucket(buckets, item);
|
||||
load.productionHours =
|
||||
load.productionHours +
|
||||
item.labhrs.aggregate.sum.mod_lb_hrs +
|
||||
item.larhrs.aggregate.sum.mod_lb_hrs;
|
||||
if (bucketId) {
|
||||
load.productionTotal[bucketId].count =
|
||||
load.productionTotal[bucketId].count + 1;
|
||||
} else {
|
||||
console.log("Uh oh, this job doesn't fit in a bucket!", item);
|
||||
}
|
||||
});
|
||||
|
||||
const itemDate = dayjs(
|
||||
item.actual_completion || item.scheduled_completion
|
||||
).format("YYYY-MM-DD");
|
||||
//Skip it, it's already completed.
|
||||
arrJobs.forEach((item) => {
|
||||
if (!item.scheduled_in) {
|
||||
console.log("JOB HAS NO SCHEDULED IN DATE.", item);
|
||||
problemJobs.push({
|
||||
...item,
|
||||
code: "Job has no scheduled in date",
|
||||
});
|
||||
}
|
||||
if (!item.actual_completion && item.actual_in && !item.inproduction) {
|
||||
problemJobs.push({
|
||||
...item,
|
||||
code: "Job has an actual in date, but no actual completion date and is not marked as in production",
|
||||
});
|
||||
}
|
||||
if (item.actual_in && dayjs(item.actual_in).isAfter(dayjs())) {
|
||||
problemJobs.push({
|
||||
...item,
|
||||
code: "Job has an actual in date set in the future",
|
||||
});
|
||||
}
|
||||
if (
|
||||
item.actual_completion &&
|
||||
dayjs(item.actual_completion).isAfter(dayjs())
|
||||
) {
|
||||
problemJobs.push({
|
||||
...item,
|
||||
code: "Job has an actual completion date set in the future",
|
||||
});
|
||||
}
|
||||
if (item.actual_completion && item.inproduction) {
|
||||
problemJobs.push({
|
||||
...item,
|
||||
code: "Job has an actual completion date but it is still marked in production",
|
||||
});
|
||||
}
|
||||
|
||||
if (!!load[itemDate]) {
|
||||
load[itemDate].allHoursOut =
|
||||
(load[itemDate].allHoursOut || 0) +
|
||||
item.labhrs.aggregate.sum.mod_lb_hrs +
|
||||
item.larhrs.aggregate.sum.mod_lb_hrs;
|
||||
//Add only the jobs that are still in production to get rid of.
|
||||
//If it's not in production, we'd subtract unnecessarily.
|
||||
load[itemDate].allJobsOut.push(item);
|
||||
const itemDate = dayjs(item.actual_in || item.scheduled_in).format(
|
||||
"YYYY-MM-DD"
|
||||
);
|
||||
|
||||
if (AddJobForSchedulingCalc) {
|
||||
load[itemDate].jobsOut.push(item);
|
||||
load[itemDate].hoursOut =
|
||||
(load[itemDate].hoursOut || 0) +
|
||||
item.labhrs.aggregate.sum.mod_lb_hrs +
|
||||
item.larhrs.aggregate.sum.mod_lb_hrs;
|
||||
const AddJobForSchedulingCalc = !item.inproduction;
|
||||
|
||||
if (!!load[itemDate]) {
|
||||
load[itemDate].allHoursIn =
|
||||
(load[itemDate].allHoursIn || 0) +
|
||||
item.labhrs.aggregate.sum.mod_lb_hrs +
|
||||
item.larhrs.aggregate.sum.mod_lb_hrs;
|
||||
|
||||
//If the job hasn't already arrived, add it to the jobs in list.
|
||||
// Make sure it also hasn't already been completed, or isn't an in and out job.
|
||||
//This prevents the duplicate counting.
|
||||
load[itemDate].allJobsIn.push(item);
|
||||
if (AddJobForSchedulingCalc) {
|
||||
load[itemDate].jobsIn.push(item);
|
||||
load[itemDate].hoursIn =
|
||||
(load[itemDate].hoursIn || 0) +
|
||||
item.labhrs.aggregate.sum.mod_lb_hrs +
|
||||
item.larhrs.aggregate.sum.mod_lb_hrs;
|
||||
}
|
||||
} else {
|
||||
load[itemDate] = {
|
||||
allJobsIn: [item],
|
||||
jobsIn: AddJobForSchedulingCalc ? [item] : [], //Same as above, only add it if it isn't already in production.
|
||||
jobsOut: [],
|
||||
allJobsOut: [],
|
||||
allHoursIn:
|
||||
item.labhrs.aggregate.sum.mod_lb_hrs +
|
||||
item.larhrs.aggregate.sum.mod_lb_hrs,
|
||||
hoursIn: AddJobForSchedulingCalc
|
||||
? item.labhrs.aggregate.sum.mod_lb_hrs +
|
||||
item.larhrs.aggregate.sum.mod_lb_hrs
|
||||
: 0,
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
compJobs.forEach((item) => {
|
||||
if (!(item.actual_completion || item.scheduled_completion))
|
||||
console.warn("JOB HAS NO COMPLETION DATE.", item);
|
||||
|
||||
const inProdJobs = prodJobs.find((p) => p.id === item.id);
|
||||
const inArrJobs = arrJobs.find((p) => p.id === item.id);
|
||||
|
||||
const AddJobForSchedulingCalc = inProdJobs || inArrJobs;
|
||||
|
||||
const itemDate = dayjs(
|
||||
item.actual_completion || item.scheduled_completion
|
||||
).format("YYYY-MM-DD");
|
||||
//Skip it, it's already completed.
|
||||
|
||||
if (!!load[itemDate]) {
|
||||
load[itemDate].allHoursOut =
|
||||
(load[itemDate].allHoursOut || 0) +
|
||||
item.labhrs.aggregate.sum.mod_lb_hrs +
|
||||
item.larhrs.aggregate.sum.mod_lb_hrs;
|
||||
//Add only the jobs that are still in production to get rid of.
|
||||
//If it's not in production, we'd subtract unnecessarily.
|
||||
load[itemDate].allJobsOut.push(item);
|
||||
|
||||
if (AddJobForSchedulingCalc) {
|
||||
load[itemDate].jobsOut.push(item);
|
||||
load[itemDate].hoursOut =
|
||||
(load[itemDate].hoursOut || 0) +
|
||||
item.labhrs.aggregate.sum.mod_lb_hrs +
|
||||
item.larhrs.aggregate.sum.mod_lb_hrs;
|
||||
}
|
||||
} else {
|
||||
load[itemDate] = {
|
||||
allJobsOut: [item],
|
||||
jobsOut: AddJobForSchedulingCalc ? [item] : [], //Same as above.
|
||||
hoursOut: AddJobForSchedulingCalc
|
||||
? item.labhrs.aggregate.sum.mod_lb_hrs +
|
||||
item.larhrs.aggregate.sum.mod_lb_hrs
|
||||
: 0,
|
||||
allHoursOut:
|
||||
item.labhrs.aggregate.sum.mod_lb_hrs +
|
||||
item.larhrs.aggregate.sum.mod_lb_hrs,
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
//Propagate the expected load to each day.
|
||||
|
||||
const range = Math.round(dayjs.duration(end.diff(today)).asDays()) + 1;
|
||||
for (var day = 0; day < range; day++) {
|
||||
const current = dayjs(today).add(day, "day").format("YYYY-MM-DD");
|
||||
const prev = dayjs(today)
|
||||
.add(day - 1, "day")
|
||||
.format("YYYY-MM-DD");
|
||||
if (!!!load[current]) {
|
||||
load[current] = {};
|
||||
}
|
||||
|
||||
if (day === 0) {
|
||||
//Starting on day 1. The load is current.
|
||||
load[current].expectedLoad = CalculateLoad(
|
||||
load.productionTotal,
|
||||
buckets,
|
||||
load[current].jobsIn || [],
|
||||
load[current].jobsOut || []
|
||||
);
|
||||
load[current].expectedJobCount =
|
||||
prodJobs.length +
|
||||
(load[current].jobsIn || []).length -
|
||||
(load[current].jobsOut || []).length;
|
||||
load[current].expectedHours =
|
||||
load.productionHours +
|
||||
(load[current].hoursIn || 0) -
|
||||
(load[current].hoursOut || 0);
|
||||
} else {
|
||||
load[current].expectedLoad = CalculateLoad(
|
||||
load[prev].expectedLoad,
|
||||
buckets,
|
||||
load[current].jobsIn || [],
|
||||
load[current].jobsOut || []
|
||||
);
|
||||
load[current].expectedJobCount =
|
||||
load[prev].expectedJobCount +
|
||||
(load[current].jobsIn || []).length -
|
||||
(load[current].jobsOut || []).length;
|
||||
load[current].expectedHours =
|
||||
load[prev].expectedHours +
|
||||
(load[current].hoursIn || 0) -
|
||||
(load[current].hoursOut || 0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
load[itemDate] = {
|
||||
allJobsOut: [item],
|
||||
jobsOut: AddJobForSchedulingCalc ? [item] : [], //Same as above.
|
||||
hoursOut: AddJobForSchedulingCalc
|
||||
? item.labhrs.aggregate.sum.mod_lb_hrs +
|
||||
item.larhrs.aggregate.sum.mod_lb_hrs
|
||||
: 0,
|
||||
allHoursOut:
|
||||
item.labhrs.aggregate.sum.mod_lb_hrs +
|
||||
item.larhrs.aggregate.sum.mod_lb_hrs,
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
//Propagate the expected load to each day.
|
||||
|
||||
const range = Math.round(dayjs.duration(end.diff(today)).asDays()) + 1;
|
||||
for (var day = 0; day < range; day++) {
|
||||
const current = dayjs(today).add(day, "day").format("YYYY-MM-DD");
|
||||
const prev = dayjs(today)
|
||||
.add(day - 1, "day")
|
||||
.format("YYYY-MM-DD");
|
||||
if (!!!load[current]) {
|
||||
load[current] = {};
|
||||
}
|
||||
|
||||
if (day === 0) {
|
||||
//Starting on day 1. The load is current.
|
||||
load[current].expectedLoad = CalculateLoad(
|
||||
load.productionTotal,
|
||||
buckets,
|
||||
load[current].jobsIn || [],
|
||||
load[current].jobsOut || []
|
||||
);
|
||||
load[current].expectedJobCount =
|
||||
prodJobs.length +
|
||||
(load[current].jobsIn || []).length -
|
||||
(load[current].jobsOut || []).length;
|
||||
load[current].expectedHours =
|
||||
load.productionHours +
|
||||
(load[current].hoursIn || 0) -
|
||||
(load[current].hoursOut || 0);
|
||||
} else {
|
||||
load[current].expectedLoad = CalculateLoad(
|
||||
load[prev].expectedLoad,
|
||||
buckets,
|
||||
load[current].jobsIn || [],
|
||||
load[current].jobsOut || []
|
||||
);
|
||||
load[current].expectedJobCount =
|
||||
load[prev].expectedJobCount +
|
||||
(load[current].jobsIn || []).length -
|
||||
(load[current].jobsOut || []).length;
|
||||
load[current].expectedHours =
|
||||
load[prev].expectedHours +
|
||||
(load[current].hoursIn || 0) -
|
||||
(load[current].hoursOut || 0);
|
||||
}
|
||||
yield put(setProblemJobs(problemJobs));
|
||||
yield put(scheduleLoadSuccess(load));
|
||||
} catch (error) {
|
||||
yield put(scheduleLoadFailure(error));
|
||||
}
|
||||
|
||||
yield put(setProblemJobs(problemJobs));
|
||||
yield put(scheduleLoadSuccess(load));
|
||||
} catch (error) {
|
||||
yield put(scheduleLoadFailure(error));
|
||||
}
|
||||
}
|
||||
|
||||
export function* onInsertAuditTrail() {
|
||||
yield takeLatest(
|
||||
ApplicationActionTypes.INSERT_AUDIT_TRAIL,
|
||||
insertAuditTrailSaga
|
||||
);
|
||||
yield takeLatest(
|
||||
ApplicationActionTypes.INSERT_AUDIT_TRAIL,
|
||||
insertAuditTrailSaga
|
||||
);
|
||||
}
|
||||
|
||||
export function* insertAuditTrailSaga({
|
||||
payload: { jobid, billid, operation },
|
||||
}) {
|
||||
const state = yield select();
|
||||
const bodyshop = state.user.bodyshop;
|
||||
const currentUser = state.user.currentUser;
|
||||
payload: {jobid, billid, operation},
|
||||
}) {
|
||||
const state = yield select();
|
||||
const bodyshop = state.user.bodyshop;
|
||||
const currentUser = state.user.currentUser;
|
||||
|
||||
const variables = {
|
||||
auditObj: {
|
||||
bodyshopid: bodyshop.id,
|
||||
jobid,
|
||||
billid,
|
||||
operation,
|
||||
useremail: currentUser.email,
|
||||
},
|
||||
};
|
||||
yield client.mutate({
|
||||
mutation: INSERT_AUDIT_TRAIL,
|
||||
variables,
|
||||
update(cache, { data }) {
|
||||
cache.modify({
|
||||
fields: {
|
||||
audit_trail(existingAuditTrail, { readField }) {
|
||||
const newAuditTrail = cache.writeQuery({
|
||||
data: data.insert_audit_trail_one,
|
||||
query: INSERT_AUDIT_TRAIL,
|
||||
variables,
|
||||
});
|
||||
return [...existingAuditTrail, newAuditTrail];
|
||||
},
|
||||
const variables = {
|
||||
auditObj: {
|
||||
bodyshopid: bodyshop.id,
|
||||
jobid,
|
||||
billid,
|
||||
operation,
|
||||
useremail: currentUser.email,
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
yield client.mutate({
|
||||
mutation: INSERT_AUDIT_TRAIL,
|
||||
variables,
|
||||
update(cache, {data}) {
|
||||
cache.modify({
|
||||
fields: {
|
||||
audit_trail(existingAuditTrail, {readField}) {
|
||||
const newAuditTrail = cache.writeQuery({
|
||||
data: data.insert_audit_trail_one,
|
||||
query: INSERT_AUDIT_TRAIL,
|
||||
variables,
|
||||
});
|
||||
return [...existingAuditTrail, newAuditTrail];
|
||||
},
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function* applicationSagas() {
|
||||
yield all([call(onCalculateScheduleLoad), call(onInsertAuditTrail)]);
|
||||
yield all([call(onCalculateScheduleLoad), call(onInsertAuditTrail)]);
|
||||
}
|
||||
|
||||
@@ -1,54 +1,54 @@
|
||||
import { createSelector } from "reselect";
|
||||
import {createSelector} from "reselect";
|
||||
|
||||
const selectApplication = (state) => state.application;
|
||||
|
||||
export const selectLoading = createSelector(
|
||||
[selectApplication],
|
||||
(application) => application.loading
|
||||
[selectApplication],
|
||||
(application) => application.loading
|
||||
);
|
||||
|
||||
export const selectBreadcrumbs = createSelector(
|
||||
[selectApplication],
|
||||
(application) => application.breadcrumbs
|
||||
[selectApplication],
|
||||
(application) => application.breadcrumbs
|
||||
);
|
||||
|
||||
export const selectRecentItems = createSelector(
|
||||
[selectApplication],
|
||||
(application) => application.recentItems
|
||||
[selectApplication],
|
||||
(application) => application.recentItems
|
||||
);
|
||||
|
||||
export const selectScheduleLoad = createSelector(
|
||||
[selectApplication],
|
||||
(application) => application.scheduleLoad.load
|
||||
[selectApplication],
|
||||
(application) => application.scheduleLoad.load
|
||||
);
|
||||
export const selectPartnerVersion = createSelector(
|
||||
[selectApplication],
|
||||
(application) => application.partnerVersion
|
||||
[selectApplication],
|
||||
(application) => application.partnerVersion
|
||||
);
|
||||
|
||||
export const selectScheduleLoadCalculating = createSelector(
|
||||
[selectApplication],
|
||||
(application) => application.scheduleLoad.calculating
|
||||
[selectApplication],
|
||||
(application) => application.scheduleLoad.calculating
|
||||
);
|
||||
|
||||
export const selectSelectedHeader = createSelector(
|
||||
[selectApplication],
|
||||
(application) => application.selectedHeader
|
||||
[selectApplication],
|
||||
(application) => application.selectedHeader
|
||||
);
|
||||
|
||||
export const selectJobReadOnly = createSelector(
|
||||
[selectApplication],
|
||||
(application) => application.jobReadOnly
|
||||
[selectApplication],
|
||||
(application) => application.jobReadOnly
|
||||
);
|
||||
export const selectOnline = createSelector(
|
||||
[selectApplication],
|
||||
(application) => application.online
|
||||
[selectApplication],
|
||||
(application) => application.online
|
||||
);
|
||||
export const selectProblemJobs = createSelector(
|
||||
[selectApplication],
|
||||
(application) => application.problemJobs
|
||||
[selectApplication],
|
||||
(application) => application.problemJobs
|
||||
);
|
||||
export const selectUpdateAvailable = createSelector(
|
||||
[selectApplication],
|
||||
(application) => application.updateAvailable
|
||||
[selectApplication],
|
||||
(application) => application.updateAvailable
|
||||
);
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
const ApplicationActionTypes = {
|
||||
START_LOADING: "START_LOADING",
|
||||
END_LOADING: "END_LOADING",
|
||||
SET_BREAD_CRUMBS: "SET_BREAD_CRUMBS",
|
||||
CALCULATE_SCHEDULE_LOAD: "CALCULATE_SCHEDULE_LOAD",
|
||||
CALCULATE_SCHEDULE_LOAD_SUCCESS: "CALCULATE_SCHEDULE_LOAD_SUCCESS",
|
||||
CALCULATE_SCHEDULE_LOAD_FAILURE: "CALCULATE_SCHEDULE_LOAD_FAILURE",
|
||||
ADD_RECENT_ITEM: "ADD_RECENT_ITEM",
|
||||
SET_SELECTED_HEADER: "SET_SELECTED_HEADER",
|
||||
SET_JOB_READONLY: "SET_JOB_READONLY",
|
||||
SET_PARTNER_VERSION: "SET_PARTNER_VERSION",
|
||||
SET_ONLINE_STATUS: "SET_ONLINE_STATUS",
|
||||
INSERT_AUDIT_TRAIL: "INSERT_AUDIT_TRAIL",
|
||||
SET_PROBLEM_JOBS: "SET_PROBLEM_JOBS",
|
||||
SET_UPDATE_AVAILABLE: "SET_UPDATE_AVAILABLE"
|
||||
START_LOADING: "START_LOADING",
|
||||
END_LOADING: "END_LOADING",
|
||||
SET_BREAD_CRUMBS: "SET_BREAD_CRUMBS",
|
||||
CALCULATE_SCHEDULE_LOAD: "CALCULATE_SCHEDULE_LOAD",
|
||||
CALCULATE_SCHEDULE_LOAD_SUCCESS: "CALCULATE_SCHEDULE_LOAD_SUCCESS",
|
||||
CALCULATE_SCHEDULE_LOAD_FAILURE: "CALCULATE_SCHEDULE_LOAD_FAILURE",
|
||||
ADD_RECENT_ITEM: "ADD_RECENT_ITEM",
|
||||
SET_SELECTED_HEADER: "SET_SELECTED_HEADER",
|
||||
SET_JOB_READONLY: "SET_JOB_READONLY",
|
||||
SET_PARTNER_VERSION: "SET_PARTNER_VERSION",
|
||||
SET_ONLINE_STATUS: "SET_ONLINE_STATUS",
|
||||
INSERT_AUDIT_TRAIL: "INSERT_AUDIT_TRAIL",
|
||||
SET_PROBLEM_JOBS: "SET_PROBLEM_JOBS",
|
||||
SET_UPDATE_AVAILABLE: "SET_UPDATE_AVAILABLE"
|
||||
};
|
||||
export default ApplicationActionTypes;
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
import EmailActionTypes from "./email.types";
|
||||
|
||||
export const toggleEmailOverlayVisible = () => ({
|
||||
type: EmailActionTypes.TOGGLE_EMAIL_OVERLAY_VISIBLE
|
||||
type: EmailActionTypes.TOGGLE_EMAIL_OVERLAY_VISIBLE
|
||||
});
|
||||
|
||||
export const setEmailOptions = options => ({
|
||||
type: EmailActionTypes.SET_EMAIL_OPTIONS,
|
||||
payload: options
|
||||
type: EmailActionTypes.SET_EMAIL_OPTIONS,
|
||||
payload: options
|
||||
});
|
||||
|
||||
export const sendEmail = email => ({
|
||||
type: EmailActionTypes.SEND_EMAIL,
|
||||
payload: email
|
||||
type: EmailActionTypes.SEND_EMAIL,
|
||||
payload: email
|
||||
});
|
||||
|
||||
export const sendEmailSuccess = options => ({
|
||||
type: EmailActionTypes.SEND_EMAIL_SUCCESS
|
||||
type: EmailActionTypes.SEND_EMAIL_SUCCESS
|
||||
});
|
||||
|
||||
export const sendEmailFailure = error => ({
|
||||
type: EmailActionTypes.SEND_EMAIL_FAILURE,
|
||||
payload: error
|
||||
type: EmailActionTypes.SEND_EMAIL_FAILURE,
|
||||
payload: error
|
||||
});
|
||||
|
||||
@@ -1,35 +1,35 @@
|
||||
import EmailActionTypes from "./email.types";
|
||||
|
||||
const INITIAL_STATE = {
|
||||
emailConfig: {
|
||||
messageOptions: {
|
||||
from: { name: "ShopName", address: "noreply@romeonline.io" },
|
||||
to: null,
|
||||
replyTo: null,
|
||||
emailConfig: {
|
||||
messageOptions: {
|
||||
from: {name: "ShopName", address: "noreply@romeonline.io"},
|
||||
to: null,
|
||||
replyTo: null,
|
||||
},
|
||||
template: {name: null, variables: {}},
|
||||
},
|
||||
template: { name: null, variables: {} },
|
||||
},
|
||||
|
||||
open: false,
|
||||
error: null,
|
||||
open: false,
|
||||
error: null,
|
||||
};
|
||||
|
||||
const emailReducer = (state = INITIAL_STATE, action) => {
|
||||
switch (action.type) {
|
||||
case EmailActionTypes.TOGGLE_EMAIL_OVERLAY_VISIBLE:
|
||||
return {
|
||||
...state,
|
||||
open: !state.open,
|
||||
};
|
||||
case EmailActionTypes.SET_EMAIL_OPTIONS:
|
||||
return {
|
||||
...state,
|
||||
emailConfig: { ...action.payload },
|
||||
open: true,
|
||||
};
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
switch (action.type) {
|
||||
case EmailActionTypes.TOGGLE_EMAIL_OVERLAY_VISIBLE:
|
||||
return {
|
||||
...state,
|
||||
open: !state.open,
|
||||
};
|
||||
case EmailActionTypes.SET_EMAIL_OPTIONS:
|
||||
return {
|
||||
...state,
|
||||
emailConfig: {...action.payload},
|
||||
open: true,
|
||||
};
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
export default emailReducer;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { all } from "redux-saga/effects";
|
||||
import {all} from "redux-saga/effects";
|
||||
// import { sendEmailFailure, sendEmailSuccess } from "./email.actions";
|
||||
// import { renderTemplate } from "../application/application.actions";
|
||||
// import EmailActionTypes from "./email.types";
|
||||
@@ -57,10 +57,10 @@ import { all } from "redux-saga/effects";
|
||||
// }
|
||||
|
||||
export function* emailSagas() {
|
||||
yield all([
|
||||
// call(onSendEmail),
|
||||
// call(onSendEmailFailure),
|
||||
// call(onSendEmailSuccess)
|
||||
//call(onSetEmailOptions),
|
||||
]);
|
||||
yield all([
|
||||
// call(onSendEmail),
|
||||
// call(onSendEmailFailure),
|
||||
// call(onSendEmailSuccess)
|
||||
//call(onSetEmailOptions),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { createSelector } from "reselect";
|
||||
import {createSelector} from "reselect";
|
||||
|
||||
const selectEmail = (state) => state.email;
|
||||
|
||||
export const selectEmailVisible = createSelector(
|
||||
[selectEmail],
|
||||
(email) => email.open
|
||||
[selectEmail],
|
||||
(email) => email.open
|
||||
);
|
||||
|
||||
export const selectEmailConfig = createSelector(
|
||||
[selectEmail],
|
||||
(email) => email.emailConfig
|
||||
[selectEmail],
|
||||
(email) => email.emailConfig
|
||||
);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
const EmailActionTypes = {
|
||||
TOGGLE_EMAIL_OVERLAY_VISIBLE: "TOGGLE_EMAIL_OVERLAY_VISIBLE",
|
||||
SET_EMAIL_OPTIONS: "SET_EMAIL_OPTIONS",
|
||||
SEND_EMAIL: "SEND_EMAIL",
|
||||
SEND_EMAIL_SUCCESS: "SEND_EMAIL_SUCCESS",
|
||||
SEND_EMAIL_FAILURE: "SEND_EMAIL_FAILURE"
|
||||
TOGGLE_EMAIL_OVERLAY_VISIBLE: "TOGGLE_EMAIL_OVERLAY_VISIBLE",
|
||||
SET_EMAIL_OPTIONS: "SET_EMAIL_OPTIONS",
|
||||
SEND_EMAIL: "SEND_EMAIL",
|
||||
SEND_EMAIL_SUCCESS: "SEND_EMAIL_SUCCESS",
|
||||
SEND_EMAIL_FAILURE: "SEND_EMAIL_FAILURE"
|
||||
};
|
||||
export default EmailActionTypes;
|
||||
|
||||
@@ -1,43 +1,43 @@
|
||||
import MediaActionTypes from "./media.types";
|
||||
|
||||
export const getJobMedia = (jobid) => ({
|
||||
type: MediaActionTypes.GET_MEDIA_FOR_JOB,
|
||||
payload: jobid,
|
||||
type: MediaActionTypes.GET_MEDIA_FOR_JOB,
|
||||
payload: jobid,
|
||||
});
|
||||
|
||||
export const getBillMedia = ({ jobid, invoice_number }) => {
|
||||
return {
|
||||
type: MediaActionTypes.GET_MEDIA_FOR_BILL,
|
||||
payload: { jobid, invoice_number },
|
||||
};
|
||||
export const getBillMedia = ({jobid, invoice_number}) => {
|
||||
return {
|
||||
type: MediaActionTypes.GET_MEDIA_FOR_BILL,
|
||||
payload: {jobid, invoice_number},
|
||||
};
|
||||
};
|
||||
|
||||
export const setJobMedia = ({ jobid, media }) => ({
|
||||
type: MediaActionTypes.SET_MEDIA_FOR_JOB,
|
||||
payload: { jobid, media },
|
||||
export const setJobMedia = ({jobid, media}) => ({
|
||||
type: MediaActionTypes.SET_MEDIA_FOR_JOB,
|
||||
payload: {jobid, media},
|
||||
});
|
||||
|
||||
export const addMediaForJob = ({ jobid, media }) => ({
|
||||
type: MediaActionTypes.ADD_MEDIA_FOR_JOB,
|
||||
payload: { jobid, media },
|
||||
export const addMediaForJob = ({jobid, media}) => ({
|
||||
type: MediaActionTypes.ADD_MEDIA_FOR_JOB,
|
||||
payload: {jobid, media},
|
||||
});
|
||||
|
||||
export const getJobMediaError = ({ error, message }) => ({
|
||||
type: MediaActionTypes.GET_MEDIA_FOR_JOB_ERROR,
|
||||
payload: { error, message },
|
||||
export const getJobMediaError = ({error, message}) => ({
|
||||
type: MediaActionTypes.GET_MEDIA_FOR_JOB_ERROR,
|
||||
payload: {error, message},
|
||||
});
|
||||
|
||||
export const toggleMediaSelected = ({ jobid, filename }) => ({
|
||||
type: MediaActionTypes.TOGGLE_MEDIA_SELECTED,
|
||||
payload: { jobid, filename },
|
||||
export const toggleMediaSelected = ({jobid, filename}) => ({
|
||||
type: MediaActionTypes.TOGGLE_MEDIA_SELECTED,
|
||||
payload: {jobid, filename},
|
||||
});
|
||||
|
||||
export const deselectAllMediaForJob = ({ jobid }) => ({
|
||||
type: MediaActionTypes.DESELECT_ALL_MEDIA_FOR_JOB,
|
||||
payload: { jobid },
|
||||
export const deselectAllMediaForJob = ({jobid}) => ({
|
||||
type: MediaActionTypes.DESELECT_ALL_MEDIA_FOR_JOB,
|
||||
payload: {jobid},
|
||||
});
|
||||
|
||||
export const selectAllmediaForJob = ({ jobid }) => ({
|
||||
type: MediaActionTypes.SELECT_ALL_MEDIA_FOR_JOB,
|
||||
payload: { jobid },
|
||||
export const selectAllmediaForJob = ({jobid}) => ({
|
||||
type: MediaActionTypes.SELECT_ALL_MEDIA_FOR_JOB,
|
||||
payload: {jobid},
|
||||
});
|
||||
|
||||
@@ -1,51 +1,51 @@
|
||||
import MediaActionTypes from "./media.types";
|
||||
|
||||
const INITIAL_STATE = { error: null };
|
||||
const INITIAL_STATE = {error: null};
|
||||
|
||||
const mediaReducer = (state = INITIAL_STATE, action) => {
|
||||
switch (action.type) {
|
||||
case MediaActionTypes.SET_MEDIA_FOR_JOB:
|
||||
return { ...state, [action.payload.jobid]: action.payload.media };
|
||||
case MediaActionTypes.GET_MEDIA_FOR_JOB_ERROR:
|
||||
return { ...state, error: action.payload };
|
||||
case MediaActionTypes.ADD_MEDIA_FOR_JOB:
|
||||
return {
|
||||
...state,
|
||||
[action.payload.jobid]: [
|
||||
...(state[action.payload.jobid] ? state[action.payload.jobid] : []),
|
||||
...(action.payload.media || []),
|
||||
],
|
||||
};
|
||||
case MediaActionTypes.TOGGLE_MEDIA_SELECTED:
|
||||
return {
|
||||
...state,
|
||||
[action.payload.jobid]: state[action.payload.jobid].map((p) => {
|
||||
if (p.filename === action.payload.filename) {
|
||||
p.isSelected = !p.isSelected;
|
||||
}
|
||||
return p;
|
||||
}),
|
||||
};
|
||||
case MediaActionTypes.SELECT_ALL_MEDIA_FOR_JOB:
|
||||
return {
|
||||
...state,
|
||||
[action.payload.jobid]: state[action.payload.jobid].map((p) => {
|
||||
p.isSelected = true;
|
||||
switch (action.type) {
|
||||
case MediaActionTypes.SET_MEDIA_FOR_JOB:
|
||||
return {...state, [action.payload.jobid]: action.payload.media};
|
||||
case MediaActionTypes.GET_MEDIA_FOR_JOB_ERROR:
|
||||
return {...state, error: action.payload};
|
||||
case MediaActionTypes.ADD_MEDIA_FOR_JOB:
|
||||
return {
|
||||
...state,
|
||||
[action.payload.jobid]: [
|
||||
...(state[action.payload.jobid] ? state[action.payload.jobid] : []),
|
||||
...(action.payload.media || []),
|
||||
],
|
||||
};
|
||||
case MediaActionTypes.TOGGLE_MEDIA_SELECTED:
|
||||
return {
|
||||
...state,
|
||||
[action.payload.jobid]: state[action.payload.jobid].map((p) => {
|
||||
if (p.filename === action.payload.filename) {
|
||||
p.isSelected = !p.isSelected;
|
||||
}
|
||||
return p;
|
||||
}),
|
||||
};
|
||||
case MediaActionTypes.SELECT_ALL_MEDIA_FOR_JOB:
|
||||
return {
|
||||
...state,
|
||||
[action.payload.jobid]: state[action.payload.jobid].map((p) => {
|
||||
p.isSelected = true;
|
||||
|
||||
return p;
|
||||
}),
|
||||
};
|
||||
case MediaActionTypes.DESELECT_ALL_MEDIA_FOR_JOB:
|
||||
return {
|
||||
...state,
|
||||
[action.payload.jobid]: state[action.payload.jobid].map((p) => {
|
||||
p.isSelected = false;
|
||||
return p;
|
||||
}),
|
||||
};
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
return p;
|
||||
}),
|
||||
};
|
||||
case MediaActionTypes.DESELECT_ALL_MEDIA_FOR_JOB:
|
||||
return {
|
||||
...state,
|
||||
[action.payload.jobid]: state[action.payload.jobid].map((p) => {
|
||||
p.isSelected = false;
|
||||
return p;
|
||||
}),
|
||||
};
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
export default mediaReducer;
|
||||
|
||||
@@ -1,120 +1,123 @@
|
||||
import { all, call, takeLatest, put, select } from "redux-saga/effects";
|
||||
import { getJobMediaError, setJobMedia } from "./media.actions";
|
||||
import {all, call, put, select, takeLatest} from "redux-saga/effects";
|
||||
import {getJobMediaError, setJobMedia} from "./media.actions";
|
||||
import MediaActionTypes from "./media.types";
|
||||
import cleanAxios from "../../utils/CleanAxios";
|
||||
import normalizeUrl from "normalize-url";
|
||||
|
||||
export function* onSetJobMedia() {
|
||||
yield takeLatest(MediaActionTypes.GET_MEDIA_FOR_JOB, getJobMedia);
|
||||
yield takeLatest(MediaActionTypes.GET_MEDIA_FOR_JOB, getJobMedia);
|
||||
}
|
||||
export function* getJobMedia({ payload: jobid }) {
|
||||
try {
|
||||
const bodyshop = yield select((state) => state.user.bodyshop);
|
||||
const localmediaserverhttp = bodyshop.localmediaserverhttp.trim();
|
||||
|
||||
if (localmediaserverhttp && localmediaserverhttp !== "") {
|
||||
const imagesFetch = yield cleanAxios.post(
|
||||
`${localmediaserverhttp}/jobs/list`,
|
||||
{
|
||||
jobid,
|
||||
},
|
||||
{ headers: { ims_token: bodyshop.localmediatoken } }
|
||||
);
|
||||
const documentsFetch = yield cleanAxios.post(
|
||||
`${localmediaserverhttp}/bills/list`,
|
||||
{
|
||||
jobid,
|
||||
},
|
||||
{ headers: { ims_token: bodyshop.localmediatoken } }
|
||||
);
|
||||
export function* getJobMedia({payload: jobid}) {
|
||||
try {
|
||||
const bodyshop = yield select((state) => state.user.bodyshop);
|
||||
const localmediaserverhttp = bodyshop.localmediaserverhttp.trim();
|
||||
|
||||
yield put(
|
||||
setJobMedia({
|
||||
jobid,
|
||||
media: [
|
||||
...imagesFetch.data.map((d, idx) => {
|
||||
return {
|
||||
...d,
|
||||
src: normalizeUrl(`${localmediaserverhttp}/${d.src}`),
|
||||
thumbnail: normalizeUrl(
|
||||
`${localmediaserverhttp}/${d.thumbnail}`
|
||||
),
|
||||
...(d.optimized && {
|
||||
optimized: normalizeUrl(
|
||||
`${localmediaserverhttp}/${d.optimized}`
|
||||
),
|
||||
}),
|
||||
isSelected: false,
|
||||
key: idx,
|
||||
};
|
||||
}),
|
||||
...documentsFetch.data.map((d, idx) => {
|
||||
return {
|
||||
...d,
|
||||
src: normalizeUrl(`${localmediaserverhttp}/${d.src}`),
|
||||
thumbnail: normalizeUrl(
|
||||
`${localmediaserverhttp}/${d.thumbnail}`
|
||||
),
|
||||
if (localmediaserverhttp && localmediaserverhttp !== "") {
|
||||
const imagesFetch = yield cleanAxios.post(
|
||||
`${localmediaserverhttp}/jobs/list`,
|
||||
{
|
||||
jobid,
|
||||
},
|
||||
{headers: {ims_token: bodyshop.localmediatoken}}
|
||||
);
|
||||
const documentsFetch = yield cleanAxios.post(
|
||||
`${localmediaserverhttp}/bills/list`,
|
||||
{
|
||||
jobid,
|
||||
},
|
||||
{headers: {ims_token: bodyshop.localmediatoken}}
|
||||
);
|
||||
|
||||
isSelected: false,
|
||||
key: idx,
|
||||
};
|
||||
}),
|
||||
],
|
||||
})
|
||||
);
|
||||
yield put(
|
||||
setJobMedia({
|
||||
jobid,
|
||||
media: [
|
||||
...imagesFetch.data.map((d, idx) => {
|
||||
return {
|
||||
...d,
|
||||
src: normalizeUrl(`${localmediaserverhttp}/${d.src}`),
|
||||
thumbnail: normalizeUrl(
|
||||
`${localmediaserverhttp}/${d.thumbnail}`
|
||||
),
|
||||
...(d.optimized && {
|
||||
optimized: normalizeUrl(
|
||||
`${localmediaserverhttp}/${d.optimized}`
|
||||
),
|
||||
}),
|
||||
isSelected: false,
|
||||
key: idx,
|
||||
};
|
||||
}),
|
||||
...documentsFetch.data.map((d, idx) => {
|
||||
return {
|
||||
...d,
|
||||
src: normalizeUrl(`${localmediaserverhttp}/${d.src}`),
|
||||
thumbnail: normalizeUrl(
|
||||
`${localmediaserverhttp}/${d.thumbnail}`
|
||||
),
|
||||
|
||||
isSelected: false,
|
||||
key: idx,
|
||||
};
|
||||
}),
|
||||
],
|
||||
})
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
yield put(getJobMediaError(error));
|
||||
}
|
||||
} catch (error) {
|
||||
yield put(getJobMediaError(error));
|
||||
}
|
||||
}
|
||||
|
||||
export function* onSetBillMedia() {
|
||||
yield takeLatest(MediaActionTypes.GET_MEDIA_FOR_BILL, getBillMedia);
|
||||
yield takeLatest(MediaActionTypes.GET_MEDIA_FOR_BILL, getBillMedia);
|
||||
}
|
||||
export function* getBillMedia({ payload: { jobid, invoice_number } }) {
|
||||
try {
|
||||
const bodyshop = yield select((state) => state.user.bodyshop);
|
||||
const localmediaserverhttp = bodyshop.localmediaserverhttp.trim();
|
||||
|
||||
if (localmediaserverhttp && localmediaserverhttp !== "") {
|
||||
const documentsFetch = yield cleanAxios.post(
|
||||
`${localmediaserverhttp}/bills/list`,
|
||||
{
|
||||
jobid,
|
||||
invoice_number,
|
||||
},
|
||||
{ headers: { ims_token: bodyshop.localmediatoken } }
|
||||
);
|
||||
export function* getBillMedia({payload: {jobid, invoice_number}}) {
|
||||
try {
|
||||
const bodyshop = yield select((state) => state.user.bodyshop);
|
||||
const localmediaserverhttp = bodyshop.localmediaserverhttp.trim();
|
||||
|
||||
yield put(
|
||||
setJobMedia({
|
||||
jobid,
|
||||
media: [
|
||||
...documentsFetch.data.map((d, idx) => {
|
||||
return {
|
||||
...d,
|
||||
src: normalizeUrl(`${localmediaserverhttp}/${d.src}`),
|
||||
thumbnail: normalizeUrl(
|
||||
`${localmediaserverhttp}/${d.thumbnail}`
|
||||
),
|
||||
...(d.optimized && {
|
||||
optimized: normalizeUrl(
|
||||
`${localmediaserverhttp}/${d.optimized}`
|
||||
),
|
||||
}),
|
||||
isSelected: false,
|
||||
key: idx,
|
||||
};
|
||||
}),
|
||||
],
|
||||
})
|
||||
);
|
||||
if (localmediaserverhttp && localmediaserverhttp !== "") {
|
||||
const documentsFetch = yield cleanAxios.post(
|
||||
`${localmediaserverhttp}/bills/list`,
|
||||
{
|
||||
jobid,
|
||||
invoice_number,
|
||||
},
|
||||
{headers: {ims_token: bodyshop.localmediatoken}}
|
||||
);
|
||||
|
||||
yield put(
|
||||
setJobMedia({
|
||||
jobid,
|
||||
media: [
|
||||
...documentsFetch.data.map((d, idx) => {
|
||||
return {
|
||||
...d,
|
||||
src: normalizeUrl(`${localmediaserverhttp}/${d.src}`),
|
||||
thumbnail: normalizeUrl(
|
||||
`${localmediaserverhttp}/${d.thumbnail}`
|
||||
),
|
||||
...(d.optimized && {
|
||||
optimized: normalizeUrl(
|
||||
`${localmediaserverhttp}/${d.optimized}`
|
||||
),
|
||||
}),
|
||||
isSelected: false,
|
||||
key: idx,
|
||||
};
|
||||
}),
|
||||
],
|
||||
})
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
yield put(getJobMediaError(error));
|
||||
}
|
||||
} catch (error) {
|
||||
yield put(getJobMediaError(error));
|
||||
}
|
||||
}
|
||||
|
||||
export function* mediaSagas() {
|
||||
yield all([call(onSetJobMedia), call(onSetBillMedia)]);
|
||||
yield all([call(onSetJobMedia), call(onSetBillMedia)]);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createSelector } from "reselect";
|
||||
import {createSelector} from "reselect";
|
||||
|
||||
const selectMedia = (state) => state.media;
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
const MediaActionTypes = {
|
||||
SET_MEDIA_FOR_JOB: "SET_MEDIA_FOR_JOB",
|
||||
GET_MEDIA_FOR_JOB: "GET_MEDIA_FOR_JOB",
|
||||
GET_MEDIA_FOR_JOB_ERROR: "GET_MEDIA_FOR_JOB_ERROR",
|
||||
ADD_MEDIA_FOR_JOB: "ADD_MEDIA_FOR_JOB",
|
||||
TOGGLE_MEDIA_SELECTED: "TOGGLE_MEDIA_SELECTED",
|
||||
GET_MEDIA_FOR_BILL: "GET_MEDIA_FOR_BILL",
|
||||
SELECT_ALL_MEDIA_FOR_JOB: "SELECT_ALL_MEDIA_FOR_JOB",
|
||||
DESELECT_ALL_MEDIA_FOR_JOB: "DESELECT_ALL_MEDIA_FOR_JOB",
|
||||
SET_MEDIA_FOR_JOB: "SET_MEDIA_FOR_JOB",
|
||||
GET_MEDIA_FOR_JOB: "GET_MEDIA_FOR_JOB",
|
||||
GET_MEDIA_FOR_JOB_ERROR: "GET_MEDIA_FOR_JOB_ERROR",
|
||||
ADD_MEDIA_FOR_JOB: "ADD_MEDIA_FOR_JOB",
|
||||
TOGGLE_MEDIA_SELECTED: "TOGGLE_MEDIA_SELECTED",
|
||||
GET_MEDIA_FOR_BILL: "GET_MEDIA_FOR_BILL",
|
||||
SELECT_ALL_MEDIA_FOR_JOB: "SELECT_ALL_MEDIA_FOR_JOB",
|
||||
DESELECT_ALL_MEDIA_FOR_JOB: "DESELECT_ALL_MEDIA_FOR_JOB",
|
||||
};
|
||||
export default MediaActionTypes;
|
||||
|
||||
@@ -1,35 +1,35 @@
|
||||
import MessagingActionTypes from "./messaging.types";
|
||||
|
||||
export const toggleChatVisible = () => ({
|
||||
type: MessagingActionTypes.TOGGLE_CHAT_VISIBLE,
|
||||
//payload: user
|
||||
type: MessagingActionTypes.TOGGLE_CHAT_VISIBLE,
|
||||
//payload: user
|
||||
});
|
||||
|
||||
export const sendMessage = (message) => ({
|
||||
type: MessagingActionTypes.SEND_MESSAGE,
|
||||
payload: message,
|
||||
type: MessagingActionTypes.SEND_MESSAGE,
|
||||
payload: message,
|
||||
});
|
||||
|
||||
export const sendMessageSuccess = (message) => ({
|
||||
type: MessagingActionTypes.SEND_MESSAGE_SUCCESS,
|
||||
payload: message,
|
||||
type: MessagingActionTypes.SEND_MESSAGE_SUCCESS,
|
||||
payload: message,
|
||||
});
|
||||
|
||||
export const sendMessageFailure = (error) => ({
|
||||
type: MessagingActionTypes.SEND_MESSAGE_FAILURE,
|
||||
payload: error,
|
||||
type: MessagingActionTypes.SEND_MESSAGE_FAILURE,
|
||||
payload: error,
|
||||
});
|
||||
export const setSelectedConversation = (conversationId) => ({
|
||||
type: MessagingActionTypes.SET_SELECTED_CONVERSATION,
|
||||
payload: conversationId,
|
||||
type: MessagingActionTypes.SET_SELECTED_CONVERSATION,
|
||||
payload: conversationId,
|
||||
});
|
||||
|
||||
export const openChatByPhone = (phoneNumber) => ({
|
||||
type: MessagingActionTypes.OPEN_CHAT_BY_PHONE,
|
||||
payload: phoneNumber,
|
||||
type: MessagingActionTypes.OPEN_CHAT_BY_PHONE,
|
||||
payload: phoneNumber,
|
||||
});
|
||||
|
||||
export const setMessage = (message) => ({
|
||||
type: MessagingActionTypes.SET_MESSAGE,
|
||||
payload: message,
|
||||
type: MessagingActionTypes.SET_MESSAGE,
|
||||
payload: message,
|
||||
});
|
||||
@@ -1,55 +1,55 @@
|
||||
import MessagingActionTypes from "./messaging.types";
|
||||
|
||||
const INITIAL_STATE = {
|
||||
open: false,
|
||||
selectedConversationId: null,
|
||||
isSending: false,
|
||||
error: null,
|
||||
message: null,
|
||||
searchingForConversation: false,
|
||||
open: false,
|
||||
selectedConversationId: null,
|
||||
isSending: false,
|
||||
error: null,
|
||||
message: null,
|
||||
searchingForConversation: false,
|
||||
};
|
||||
|
||||
const messagingReducer = (state = INITIAL_STATE, action) => {
|
||||
switch (action.type) {
|
||||
case MessagingActionTypes.SET_MESSAGE:
|
||||
return { ...state, message: action.payload };
|
||||
case MessagingActionTypes.TOGGLE_CHAT_VISIBLE:
|
||||
return {
|
||||
...state,
|
||||
open: !state.open,
|
||||
};
|
||||
case MessagingActionTypes.OPEN_CHAT_BY_PHONE:
|
||||
return {
|
||||
...state,
|
||||
searchingForConversation: true,
|
||||
};
|
||||
case MessagingActionTypes.SET_SELECTED_CONVERSATION:
|
||||
return {
|
||||
...state,
|
||||
open: true,
|
||||
searchingForConversation: false,
|
||||
selectedConversationId: action.payload,
|
||||
};
|
||||
case MessagingActionTypes.SEND_MESSAGE:
|
||||
return {
|
||||
...state,
|
||||
error: null,
|
||||
isSending: true,
|
||||
};
|
||||
case MessagingActionTypes.SEND_MESSAGE_SUCCESS:
|
||||
return {
|
||||
...state,
|
||||
message: "",
|
||||
isSending: false,
|
||||
};
|
||||
case MessagingActionTypes.SEND_MESSAGE_FAILURE:
|
||||
return {
|
||||
...state,
|
||||
error: action.payload,
|
||||
};
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
switch (action.type) {
|
||||
case MessagingActionTypes.SET_MESSAGE:
|
||||
return {...state, message: action.payload};
|
||||
case MessagingActionTypes.TOGGLE_CHAT_VISIBLE:
|
||||
return {
|
||||
...state,
|
||||
open: !state.open,
|
||||
};
|
||||
case MessagingActionTypes.OPEN_CHAT_BY_PHONE:
|
||||
return {
|
||||
...state,
|
||||
searchingForConversation: true,
|
||||
};
|
||||
case MessagingActionTypes.SET_SELECTED_CONVERSATION:
|
||||
return {
|
||||
...state,
|
||||
open: true,
|
||||
searchingForConversation: false,
|
||||
selectedConversationId: action.payload,
|
||||
};
|
||||
case MessagingActionTypes.SEND_MESSAGE:
|
||||
return {
|
||||
...state,
|
||||
error: null,
|
||||
isSending: true,
|
||||
};
|
||||
case MessagingActionTypes.SEND_MESSAGE_SUCCESS:
|
||||
return {
|
||||
...state,
|
||||
message: "",
|
||||
isSending: false,
|
||||
};
|
||||
case MessagingActionTypes.SEND_MESSAGE_FAILURE:
|
||||
return {
|
||||
...state,
|
||||
error: action.payload,
|
||||
};
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
export default messagingReducer;
|
||||
|
||||
@@ -1,112 +1,109 @@
|
||||
import axios from "axios";
|
||||
import parsePhoneNumber from "libphonenumber-js";
|
||||
import { all, call, put, select, takeLatest } from "redux-saga/effects";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
import {
|
||||
CONVERSATION_ID_BY_PHONE,
|
||||
CREATE_CONVERSATION,
|
||||
} from "../../graphql/conversations.queries";
|
||||
import { INSERT_CONVERSATION_TAG } from "../../graphql/job-conversations.queries";
|
||||
import {all, call, put, select, takeLatest} from "redux-saga/effects";
|
||||
import {logImEXEvent} from "../../firebase/firebase.utils";
|
||||
import {CONVERSATION_ID_BY_PHONE, CREATE_CONVERSATION,} from "../../graphql/conversations.queries";
|
||||
import {INSERT_CONVERSATION_TAG} from "../../graphql/job-conversations.queries";
|
||||
import client from "../../utils/GraphQLClient";
|
||||
import { selectBodyshop } from "../user/user.selectors";
|
||||
import {
|
||||
sendMessageFailure,
|
||||
sendMessageSuccess,
|
||||
setSelectedConversation,
|
||||
} from "./messaging.actions";
|
||||
import {selectBodyshop} from "../user/user.selectors";
|
||||
import {sendMessageFailure, sendMessageSuccess, setSelectedConversation,} from "./messaging.actions";
|
||||
import MessagingActionTypes from "./messaging.types";
|
||||
|
||||
export function* onToggleChatVisible() {
|
||||
yield takeLatest(MessagingActionTypes.TOGGLE_CHAT_VISIBLE, toggleChatLogging);
|
||||
yield takeLatest(MessagingActionTypes.TOGGLE_CHAT_VISIBLE, toggleChatLogging);
|
||||
}
|
||||
|
||||
export function* toggleChatLogging() {
|
||||
try {
|
||||
yield logImEXEvent("messaging_toggle_popup");
|
||||
} catch (error) {
|
||||
console.log("Error in sendMessage saga.", error);
|
||||
}
|
||||
}
|
||||
export function* onOpenChatByPhone() {
|
||||
yield takeLatest(MessagingActionTypes.OPEN_CHAT_BY_PHONE, openChatByPhone);
|
||||
}
|
||||
export function* openChatByPhone({ payload }) {
|
||||
logImEXEvent("messaging_open_by_phone");
|
||||
const { phone_num, jobid } = payload;
|
||||
|
||||
const p = parsePhoneNumber(phone_num, "CA");
|
||||
const bodyshop = yield select(selectBodyshop);
|
||||
try {
|
||||
const {
|
||||
data: { conversations },
|
||||
} = yield client.query({
|
||||
query: CONVERSATION_ID_BY_PHONE,
|
||||
variables: { phone: p.number },
|
||||
});
|
||||
|
||||
if (conversations.length === 0) {
|
||||
const {
|
||||
data: {
|
||||
insert_conversations: { returning: newConversationsId },
|
||||
},
|
||||
} = yield client.mutate({
|
||||
mutation: CREATE_CONVERSATION,
|
||||
variables: {
|
||||
conversation: [
|
||||
{
|
||||
phone_num: p.number,
|
||||
bodyshopid: bodyshop.id,
|
||||
job_conversations: jobid ? { data: { jobid: jobid } } : null,
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
yield put(setSelectedConversation(newConversationsId[0].id));
|
||||
} else if (conversations.length === 1) {
|
||||
//got the ID. Open it.
|
||||
yield put(setSelectedConversation(conversations[0].id));
|
||||
|
||||
//Check to see if this job ID is already a child of it. If not add the tag.
|
||||
if (
|
||||
jobid &&
|
||||
!conversations[0].job_conversations.find((jc) => jc.jobid === jobid)
|
||||
)
|
||||
yield client.mutate({
|
||||
mutation: INSERT_CONVERSATION_TAG,
|
||||
variables: {
|
||||
conversationId: conversations[0].id,
|
||||
jobId: jobid,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
console.log("ERROR: Multiple conversations found. ");
|
||||
yield put(setSelectedConversation(null));
|
||||
try {
|
||||
yield logImEXEvent("messaging_toggle_popup");
|
||||
} catch (error) {
|
||||
console.log("Error in sendMessage saga.", error);
|
||||
}
|
||||
}
|
||||
|
||||
export function* onOpenChatByPhone() {
|
||||
yield takeLatest(MessagingActionTypes.OPEN_CHAT_BY_PHONE, openChatByPhone);
|
||||
}
|
||||
|
||||
export function* openChatByPhone({payload}) {
|
||||
logImEXEvent("messaging_open_by_phone");
|
||||
const {phone_num, jobid} = payload;
|
||||
|
||||
const p = parsePhoneNumber(phone_num, "CA");
|
||||
const bodyshop = yield select(selectBodyshop);
|
||||
try {
|
||||
const {
|
||||
data: {conversations},
|
||||
} = yield client.query({
|
||||
query: CONVERSATION_ID_BY_PHONE,
|
||||
variables: {phone: p.number},
|
||||
});
|
||||
|
||||
if (conversations.length === 0) {
|
||||
const {
|
||||
data: {
|
||||
insert_conversations: {returning: newConversationsId},
|
||||
},
|
||||
} = yield client.mutate({
|
||||
mutation: CREATE_CONVERSATION,
|
||||
variables: {
|
||||
conversation: [
|
||||
{
|
||||
phone_num: p.number,
|
||||
bodyshopid: bodyshop.id,
|
||||
job_conversations: jobid ? {data: {jobid: jobid}} : null,
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
yield put(setSelectedConversation(newConversationsId[0].id));
|
||||
} else if (conversations.length === 1) {
|
||||
//got the ID. Open it.
|
||||
yield put(setSelectedConversation(conversations[0].id));
|
||||
|
||||
//Check to see if this job ID is already a child of it. If not add the tag.
|
||||
if (
|
||||
jobid &&
|
||||
!conversations[0].job_conversations.find((jc) => jc.jobid === jobid)
|
||||
)
|
||||
yield client.mutate({
|
||||
mutation: INSERT_CONVERSATION_TAG,
|
||||
variables: {
|
||||
conversationId: conversations[0].id,
|
||||
jobId: jobid,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
console.log("ERROR: Multiple conversations found. ");
|
||||
yield put(setSelectedConversation(null));
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("Error in sendMessage saga.", error);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("Error in sendMessage saga.", error);
|
||||
}
|
||||
}
|
||||
|
||||
export function* onSendMessage() {
|
||||
yield takeLatest(MessagingActionTypes.SEND_MESSAGE, sendMessage);
|
||||
yield takeLatest(MessagingActionTypes.SEND_MESSAGE, sendMessage);
|
||||
}
|
||||
export function* sendMessage({ payload }) {
|
||||
try {
|
||||
const response = yield call(axios.post, "/sms/send", payload);
|
||||
if (response.status === 200) {
|
||||
yield put(sendMessageSuccess(payload));
|
||||
} else {
|
||||
yield put(sendMessageFailure(response.data));
|
||||
|
||||
export function* sendMessage({payload}) {
|
||||
try {
|
||||
const response = yield call(axios.post, "/sms/send", payload);
|
||||
if (response.status === 200) {
|
||||
yield put(sendMessageSuccess(payload));
|
||||
} else {
|
||||
yield put(sendMessageFailure(response.data));
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("Error in sendMessage saga.", error);
|
||||
yield put(sendMessageFailure(error));
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("Error in sendMessage saga.", error);
|
||||
yield put(sendMessageFailure(error));
|
||||
}
|
||||
}
|
||||
|
||||
export function* messagingSagas() {
|
||||
yield all([
|
||||
call(onSendMessage),
|
||||
call(onOpenChatByPhone),
|
||||
call(onToggleChatVisible),
|
||||
]);
|
||||
yield all([
|
||||
call(onSendMessage),
|
||||
call(onOpenChatByPhone),
|
||||
call(onToggleChatVisible),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -1,33 +1,33 @@
|
||||
import { createSelector } from "reselect";
|
||||
import {createSelector} from "reselect";
|
||||
|
||||
const selectMessaging = (state) => state.messaging;
|
||||
|
||||
export const selectChatVisible = createSelector(
|
||||
[selectMessaging],
|
||||
(messaging) => messaging.open
|
||||
[selectMessaging],
|
||||
(messaging) => messaging.open
|
||||
);
|
||||
|
||||
export const selectIsSending = createSelector(
|
||||
[selectMessaging],
|
||||
(messaging) => messaging.isSending
|
||||
[selectMessaging],
|
||||
(messaging) => messaging.isSending
|
||||
);
|
||||
|
||||
export const selectError = createSelector(
|
||||
[selectMessaging],
|
||||
(messaging) => messaging.error
|
||||
[selectMessaging],
|
||||
(messaging) => messaging.error
|
||||
);
|
||||
|
||||
export const selectSelectedConversation = createSelector(
|
||||
[selectMessaging],
|
||||
(messaging) => messaging.selectedConversationId
|
||||
[selectMessaging],
|
||||
(messaging) => messaging.selectedConversationId
|
||||
);
|
||||
|
||||
export const selectMessage = createSelector(
|
||||
[selectMessaging],
|
||||
(messaging) => messaging.message
|
||||
[selectMessaging],
|
||||
(messaging) => messaging.message
|
||||
);
|
||||
|
||||
export const searchingForConversation = createSelector(
|
||||
[selectMessaging],
|
||||
(messaging) => messaging.searchingForConversation
|
||||
[selectMessaging],
|
||||
(messaging) => messaging.searchingForConversation
|
||||
);
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
const MessagingActionTypes = {
|
||||
TOGGLE_CHAT_VISIBLE: "TOGGLE_CHAT_VISIBLE",
|
||||
SEND_MESSAGE: "SEND_MESSAGE",
|
||||
SEND_MESSAGE_SUCCESS: "SEND_MESSAGE_SUCCESS",
|
||||
SEND_MESSAGE_FAILURE: "SEND_MESSAGE_FAILURE",
|
||||
SET_SELECTED_CONVERSATION: "SET_SELECTED_CONVERSATION",
|
||||
OPEN_CHAT_BY_PHONE: "OPEN_CHAT_BY_PHONE",
|
||||
SET_MESSAGE: "SET_MESSAGE",
|
||||
TOGGLE_CHAT_VISIBLE: "TOGGLE_CHAT_VISIBLE",
|
||||
SEND_MESSAGE: "SEND_MESSAGE",
|
||||
SEND_MESSAGE_SUCCESS: "SEND_MESSAGE_SUCCESS",
|
||||
SEND_MESSAGE_FAILURE: "SEND_MESSAGE_FAILURE",
|
||||
SET_SELECTED_CONVERSATION: "SET_SELECTED_CONVERSATION",
|
||||
OPEN_CHAT_BY_PHONE: "OPEN_CHAT_BY_PHONE",
|
||||
SET_MESSAGE: "SET_MESSAGE",
|
||||
};
|
||||
export default MessagingActionTypes;
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import ModalsActionTypes from "./modals.types";
|
||||
|
||||
export const toggleModalVisible = modalName => ({
|
||||
type: ModalsActionTypes.TOGGLE_MODAL_VISIBLE,
|
||||
payload: modalName
|
||||
type: ModalsActionTypes.TOGGLE_MODAL_VISIBLE,
|
||||
payload: modalName
|
||||
});
|
||||
|
||||
//Modal Context: {context (context object), modal(name of modal)}
|
||||
export const setModalContext = modalContext => ({
|
||||
type: ModalsActionTypes.SET_MODAL_CONTEXT,
|
||||
payload: modalContext
|
||||
type: ModalsActionTypes.SET_MODAL_CONTEXT,
|
||||
payload: modalContext
|
||||
});
|
||||
|
||||
@@ -1,56 +1,56 @@
|
||||
import ModalsActionTypes from "./modals.types";
|
||||
|
||||
const baseModal = {
|
||||
open: false,
|
||||
context: {},
|
||||
actions: {
|
||||
refetch: null,
|
||||
},
|
||||
open: false,
|
||||
context: {},
|
||||
actions: {
|
||||
refetch: null,
|
||||
},
|
||||
};
|
||||
|
||||
const INITIAL_STATE = {
|
||||
jobLineEdit: { ...baseModal },
|
||||
billEnter: { ...baseModal },
|
||||
courtesyCarReturn: { ...baseModal },
|
||||
noteUpsert: { ...baseModal },
|
||||
schedule: { ...baseModal },
|
||||
partsOrder: { ...baseModal },
|
||||
timeTicket: { ...baseModal },
|
||||
timeTicketTask: { ...baseModal },
|
||||
printCenter: { ...baseModal },
|
||||
reconciliation: { ...baseModal },
|
||||
payment: { ...baseModal },
|
||||
jobCosting: { ...baseModal },
|
||||
reportCenter: { ...baseModal },
|
||||
partsReceive: { ...baseModal },
|
||||
contractFinder: { ...baseModal },
|
||||
inventoryUpsert: { ...baseModal },
|
||||
ca_bc_eftTableConvert: { ...baseModal },
|
||||
cardPayment: { ...baseModal },
|
||||
jobLineEdit: {...baseModal},
|
||||
billEnter: {...baseModal},
|
||||
courtesyCarReturn: {...baseModal},
|
||||
noteUpsert: {...baseModal},
|
||||
schedule: {...baseModal},
|
||||
partsOrder: {...baseModal},
|
||||
timeTicket: {...baseModal},
|
||||
timeTicketTask: {...baseModal},
|
||||
printCenter: {...baseModal},
|
||||
reconciliation: {...baseModal},
|
||||
payment: {...baseModal},
|
||||
jobCosting: {...baseModal},
|
||||
reportCenter: {...baseModal},
|
||||
partsReceive: {...baseModal},
|
||||
contractFinder: {...baseModal},
|
||||
inventoryUpsert: {...baseModal},
|
||||
ca_bc_eftTableConvert: {...baseModal},
|
||||
cardPayment: {...baseModal},
|
||||
};
|
||||
|
||||
const modalsReducer = (state = INITIAL_STATE, action) => {
|
||||
switch (action.type) {
|
||||
case ModalsActionTypes.TOGGLE_MODAL_VISIBLE:
|
||||
return {
|
||||
...state,
|
||||
[action.payload]: {
|
||||
...state[action.payload],
|
||||
open: !state[action.payload].open,
|
||||
},
|
||||
};
|
||||
case ModalsActionTypes.SET_MODAL_CONTEXT:
|
||||
return {
|
||||
...state,
|
||||
[action.payload.modal]: {
|
||||
...state[action.payload.modal],
|
||||
...action.payload.context,
|
||||
open: true,
|
||||
},
|
||||
};
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
switch (action.type) {
|
||||
case ModalsActionTypes.TOGGLE_MODAL_VISIBLE:
|
||||
return {
|
||||
...state,
|
||||
[action.payload]: {
|
||||
...state[action.payload],
|
||||
open: !state[action.payload].open,
|
||||
},
|
||||
};
|
||||
case ModalsActionTypes.SET_MODAL_CONTEXT:
|
||||
return {
|
||||
...state,
|
||||
[action.payload.modal]: {
|
||||
...state[action.payload.modal],
|
||||
...action.payload.context,
|
||||
open: true,
|
||||
},
|
||||
};
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
export default modalsReducer;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { all } from "redux-saga/effects";
|
||||
import {all} from "redux-saga/effects";
|
||||
|
||||
export function* modalsSagas() {
|
||||
yield all([
|
||||
//call(onSendEmail),
|
||||
]);
|
||||
yield all([
|
||||
//call(onSendEmail),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -1,90 +1,90 @@
|
||||
import { createSelector } from "reselect";
|
||||
import {createSelector} from "reselect";
|
||||
|
||||
const selectModals = (state) => state.modals;
|
||||
|
||||
export const selectJobLineEditModal = createSelector(
|
||||
[selectModals],
|
||||
(modals) => modals.jobLineEdit
|
||||
[selectModals],
|
||||
(modals) => modals.jobLineEdit
|
||||
);
|
||||
|
||||
export const selectBillEnterModal = createSelector(
|
||||
[selectModals],
|
||||
(modals) => modals.billEnter
|
||||
[selectModals],
|
||||
(modals) => modals.billEnter
|
||||
);
|
||||
|
||||
export const selectCourtesyCarReturn = createSelector(
|
||||
[selectModals],
|
||||
(modals) => modals.courtesyCarReturn
|
||||
[selectModals],
|
||||
(modals) => modals.courtesyCarReturn
|
||||
);
|
||||
|
||||
export const selectNoteUpsert = createSelector(
|
||||
[selectModals],
|
||||
(modals) => modals.noteUpsert
|
||||
[selectModals],
|
||||
(modals) => modals.noteUpsert
|
||||
);
|
||||
|
||||
export const selectSchedule = createSelector(
|
||||
[selectModals],
|
||||
(modals) => modals.schedule
|
||||
[selectModals],
|
||||
(modals) => modals.schedule
|
||||
);
|
||||
|
||||
export const selectPartsOrder = createSelector(
|
||||
[selectModals],
|
||||
(modals) => modals.partsOrder
|
||||
[selectModals],
|
||||
(modals) => modals.partsOrder
|
||||
);
|
||||
|
||||
export const selectTimeTicket = createSelector(
|
||||
[selectModals],
|
||||
(modals) => modals.timeTicket
|
||||
[selectModals],
|
||||
(modals) => modals.timeTicket
|
||||
);
|
||||
export const selectTimeTicketTasks = createSelector(
|
||||
[selectModals],
|
||||
(modals) => modals.timeTicketTask
|
||||
[selectModals],
|
||||
(modals) => modals.timeTicketTask
|
||||
);
|
||||
|
||||
export const selectPrintCenter = createSelector(
|
||||
[selectModals],
|
||||
(modals) => modals.printCenter
|
||||
[selectModals],
|
||||
(modals) => modals.printCenter
|
||||
);
|
||||
|
||||
export const selectReconciliation = createSelector(
|
||||
[selectModals],
|
||||
(modals) => modals.reconciliation
|
||||
[selectModals],
|
||||
(modals) => modals.reconciliation
|
||||
);
|
||||
export const selectPayment = createSelector(
|
||||
[selectModals],
|
||||
(modals) => modals.payment
|
||||
[selectModals],
|
||||
(modals) => modals.payment
|
||||
);
|
||||
|
||||
export const selectJobCosting = createSelector(
|
||||
[selectModals],
|
||||
(modals) => modals.jobCosting
|
||||
[selectModals],
|
||||
(modals) => modals.jobCosting
|
||||
);
|
||||
|
||||
export const selectReportCenter = createSelector(
|
||||
[selectModals],
|
||||
(modals) => modals.reportCenter
|
||||
[selectModals],
|
||||
(modals) => modals.reportCenter
|
||||
);
|
||||
|
||||
export const selectPartsReceive = createSelector(
|
||||
[selectModals],
|
||||
(modals) => modals.partsReceive
|
||||
[selectModals],
|
||||
(modals) => modals.partsReceive
|
||||
);
|
||||
|
||||
export const selectContractFinder = createSelector(
|
||||
[selectModals],
|
||||
(modals) => modals.contractFinder
|
||||
[selectModals],
|
||||
(modals) => modals.contractFinder
|
||||
);
|
||||
export const selectInventoryUpsert = createSelector(
|
||||
[selectModals],
|
||||
(modals) => modals.inventoryUpsert
|
||||
[selectModals],
|
||||
(modals) => modals.inventoryUpsert
|
||||
);
|
||||
|
||||
export const selectCaBcEtfTableConvert = createSelector(
|
||||
[selectModals],
|
||||
(modals) => modals.ca_bc_eftTableConvert
|
||||
[selectModals],
|
||||
(modals) => modals.ca_bc_eftTableConvert
|
||||
);
|
||||
|
||||
export const selectCardPayment = createSelector(
|
||||
[selectModals],
|
||||
(modals) => modals.cardPayment
|
||||
[selectModals],
|
||||
(modals) => modals.cardPayment
|
||||
);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const ModalActionTypes = {
|
||||
TOGGLE_MODAL_VISIBLE: "TOGGLE_MODAL_VISIBLE",
|
||||
SET_MODAL_CONTEXT: "SET_MODAL_CONTEXT"
|
||||
TOGGLE_MODAL_VISIBLE: "TOGGLE_MODAL_VISIBLE",
|
||||
SET_MODAL_CONTEXT: "SET_MODAL_CONTEXT"
|
||||
};
|
||||
export default ModalActionTypes;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { combineReducers } from "redux";
|
||||
import { persistReducer } from "redux-persist";
|
||||
import {combineReducers} from "redux";
|
||||
import {persistReducer} from "redux-persist";
|
||||
import storage from "redux-persist/lib/storage";
|
||||
import { withReduxStateSync } from "redux-state-sync";
|
||||
import {withReduxStateSync} from "redux-state-sync";
|
||||
import applicationReducer from "./application/application.reducer";
|
||||
import emailReducer from "./email/email.reducer";
|
||||
import mediaReducer from "./media/media.reducer";
|
||||
@@ -18,23 +18,23 @@ import userReducer from "./user/user.reducer";
|
||||
// };
|
||||
|
||||
const applicationPersistConfig = {
|
||||
key: "v",
|
||||
storage: storage,
|
||||
whitelist: ["recentItems"],
|
||||
key: "v",
|
||||
storage: storage,
|
||||
whitelist: ["recentItems"],
|
||||
};
|
||||
|
||||
const rootReducer = combineReducers({
|
||||
user: userReducer,
|
||||
messaging: messagingReducer,
|
||||
email: emailReducer,
|
||||
modals: modalsReducer,
|
||||
application: persistReducer(applicationPersistConfig, applicationReducer),
|
||||
tech: techReducer,
|
||||
media: mediaReducer,
|
||||
user: userReducer,
|
||||
messaging: messagingReducer,
|
||||
email: emailReducer,
|
||||
modals: modalsReducer,
|
||||
application: persistReducer(applicationPersistConfig, applicationReducer),
|
||||
tech: techReducer,
|
||||
media: mediaReducer,
|
||||
});
|
||||
|
||||
export default withReduxStateSync(
|
||||
// persistReducer(persistConfig,
|
||||
rootReducer
|
||||
//)
|
||||
// persistReducer(persistConfig,
|
||||
rootReducer
|
||||
//)
|
||||
);
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
import { all, call } from "redux-saga/effects";
|
||||
import {all, call} from "redux-saga/effects";
|
||||
|
||||
import { userSagas } from "./user/user.sagas";
|
||||
import { messagingSagas } from "./messaging/messaging.sagas";
|
||||
import { emailSagas } from "./email/email.sagas";
|
||||
import { modalsSagas } from "./modals/modals.sagas";
|
||||
import { applicationSagas } from "./application/application.sagas";
|
||||
import { techSagas } from "./tech/tech.sagas";
|
||||
import { mediaSagas } from "./media/media.sagas";
|
||||
import {userSagas} from "./user/user.sagas";
|
||||
import {messagingSagas} from "./messaging/messaging.sagas";
|
||||
import {emailSagas} from "./email/email.sagas";
|
||||
import {modalsSagas} from "./modals/modals.sagas";
|
||||
import {applicationSagas} from "./application/application.sagas";
|
||||
import {techSagas} from "./tech/tech.sagas";
|
||||
import {mediaSagas} from "./media/media.sagas";
|
||||
|
||||
export default function* rootSaga() {
|
||||
yield all([
|
||||
call(userSagas),
|
||||
call(messagingSagas),
|
||||
call(emailSagas),
|
||||
call(modalsSagas),
|
||||
call(applicationSagas),
|
||||
call(techSagas),
|
||||
call(mediaSagas),
|
||||
]);
|
||||
yield all([
|
||||
call(userSagas),
|
||||
call(messagingSagas),
|
||||
call(emailSagas),
|
||||
call(modalsSagas),
|
||||
call(applicationSagas),
|
||||
call(techSagas),
|
||||
call(mediaSagas),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -1,55 +1,50 @@
|
||||
import { configureStore } from '@reduxjs/toolkit';
|
||||
import {
|
||||
persistStore,
|
||||
} from "redux-persist";
|
||||
import { createLogger } from "redux-logger";
|
||||
import {configureStore} from '@reduxjs/toolkit';
|
||||
import {persistStore,} from "redux-persist";
|
||||
import {createLogger} from "redux-logger";
|
||||
import createSagaMiddleware from "redux-saga";
|
||||
import {
|
||||
createStateSyncMiddleware,
|
||||
initMessageListener,
|
||||
} from "redux-state-sync";
|
||||
import {createStateSyncMiddleware, initMessageListener,} from "redux-state-sync";
|
||||
|
||||
import rootReducer from "./root.reducer";
|
||||
import rootSaga from "./root.saga";
|
||||
import * as Sentry from "@sentry/react";
|
||||
|
||||
const sentryReduxEnhancer = Sentry.createReduxEnhancer({
|
||||
// Optionally pass options
|
||||
// Optionally pass options
|
||||
});
|
||||
const sagaMiddleWare = createSagaMiddleware();
|
||||
|
||||
const reduxSyncConfig = {
|
||||
whitelist: [
|
||||
"ADD_RECENT_ITEM", //"SET_SHOP_DETAILS"
|
||||
],
|
||||
whitelist: [
|
||||
"ADD_RECENT_ITEM", //"SET_SHOP_DETAILS"
|
||||
],
|
||||
};
|
||||
|
||||
const middlewares = [
|
||||
sagaMiddleWare,
|
||||
createStateSyncMiddleware(reduxSyncConfig),
|
||||
sagaMiddleWare,
|
||||
createStateSyncMiddleware(reduxSyncConfig),
|
||||
];
|
||||
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
middlewares.push(createLogger({ collapsed: true, diff: true }));
|
||||
middlewares.push(createLogger({collapsed: true, diff: true}));
|
||||
}
|
||||
|
||||
export const store = configureStore({
|
||||
reducer: rootReducer,
|
||||
middleware: (getDefaultMiddleware) => getDefaultMiddleware({
|
||||
serializableCheck: false,
|
||||
}).concat(middlewares),
|
||||
// middleware: middlewares,
|
||||
devTools: process.env.NODE_ENV !== 'production',
|
||||
enhancers: (getDefaultEnhancers) => getDefaultEnhancers().concat(sentryReduxEnhancer)
|
||||
reducer: rootReducer,
|
||||
middleware: (getDefaultMiddleware) => getDefaultMiddleware({
|
||||
serializableCheck: false,
|
||||
}).concat(middlewares),
|
||||
// middleware: middlewares,
|
||||
devTools: process.env.NODE_ENV !== 'production',
|
||||
enhancers: (getDefaultEnhancers) => getDefaultEnhancers().concat(sentryReduxEnhancer)
|
||||
});
|
||||
|
||||
sagaMiddleWare.run(rootSaga);
|
||||
initMessageListener(store);
|
||||
|
||||
export const persistor = persistStore(store);
|
||||
const e = { store, persistStore };
|
||||
const e = {store, persistStore};
|
||||
export default e;
|
||||
|
||||
if (window.Cypress) {
|
||||
window.store = store;
|
||||
window.store = store;
|
||||
}
|
||||
@@ -1,20 +1,20 @@
|
||||
import TechActionTypes from "./tech.types";
|
||||
|
||||
export const techLoginStart = ({ employeeid, pin }) => ({
|
||||
type: TechActionTypes.TECH_LOGIN_START,
|
||||
payload: { employeeid, pin },
|
||||
export const techLoginStart = ({employeeid, pin}) => ({
|
||||
type: TechActionTypes.TECH_LOGIN_START,
|
||||
payload: {employeeid, pin},
|
||||
});
|
||||
|
||||
export const techLoginSuccess = (tech) => ({
|
||||
type: TechActionTypes.TECH_LOGIN_SUCCESS,
|
||||
payload: tech,
|
||||
type: TechActionTypes.TECH_LOGIN_SUCCESS,
|
||||
payload: tech,
|
||||
});
|
||||
|
||||
export const techLoginFailure = (error) => ({
|
||||
type: TechActionTypes.TECH_LOGIN_FAILURE,
|
||||
payload: error,
|
||||
type: TechActionTypes.TECH_LOGIN_FAILURE,
|
||||
payload: error,
|
||||
});
|
||||
|
||||
export const techLogout = () => ({
|
||||
type: TechActionTypes.TECH_LOGOUT,
|
||||
type: TechActionTypes.TECH_LOGOUT,
|
||||
});
|
||||
|
||||
@@ -1,45 +1,46 @@
|
||||
import TechActionTypes from "./tech.types";
|
||||
|
||||
const INITIAL_STATE = {
|
||||
technician: null,
|
||||
// technician: {
|
||||
// employee_number: "101",
|
||||
// first_name: "***HARDCODED",
|
||||
// last_name: "IN REDUCER***",
|
||||
// },
|
||||
loginLoading: false,
|
||||
loginError: null,
|
||||
technician: null,
|
||||
// technician: {
|
||||
// employee_number: "101",
|
||||
// first_name: "***HARDCODED",
|
||||
// last_name: "IN REDUCER***",
|
||||
// },
|
||||
loginLoading: false,
|
||||
loginError: null,
|
||||
};
|
||||
|
||||
const applicationReducer = (state = INITIAL_STATE, action) => {
|
||||
switch (action.type) {
|
||||
case TechActionTypes.TECH_LOGOUT:
|
||||
return {
|
||||
...state,
|
||||
technician: null,
|
||||
loginError: null,
|
||||
};
|
||||
case TechActionTypes.TECH_LOGIN_START:
|
||||
return {
|
||||
...state,
|
||||
loginLoading: true,
|
||||
};
|
||||
case TechActionTypes.TECH_LOGIN_SUCCESS:
|
||||
return {
|
||||
...state,
|
||||
technician: action.payload,
|
||||
loginLoading: false,
|
||||
loginError: false,
|
||||
};
|
||||
case TechActionTypes.TECH_LOGIN_FAILURE:
|
||||
return {
|
||||
...state,
|
||||
loginError: action.payload,
|
||||
loginLoading: false,
|
||||
};
|
||||
switch (action.type) {
|
||||
case TechActionTypes.TECH_LOGOUT:
|
||||
return {
|
||||
...state,
|
||||
technician: null,
|
||||
loginError: null,
|
||||
};
|
||||
case TechActionTypes.TECH_LOGIN_START:
|
||||
return {
|
||||
...state,
|
||||
loginLoading: true,
|
||||
};
|
||||
case TechActionTypes.TECH_LOGIN_SUCCESS:
|
||||
return {
|
||||
...state,
|
||||
technician: action.payload,
|
||||
loginLoading: false,
|
||||
loginError: false,
|
||||
};
|
||||
case TechActionTypes.TECH_LOGIN_FAILURE:
|
||||
return {
|
||||
...state,
|
||||
loginError: action.payload,
|
||||
loginLoading: false,
|
||||
};
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
export default applicationReducer;
|
||||
|
||||
@@ -1,36 +1,37 @@
|
||||
import axios from "axios";
|
||||
import { all, call, put, select, takeLatest } from "redux-saga/effects";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
import { selectBodyshop } from "../user/user.selectors";
|
||||
import { techLoginFailure, techLoginSuccess } from "./tech.actions";
|
||||
import {all, call, put, select, takeLatest} from "redux-saga/effects";
|
||||
import {logImEXEvent} from "../../firebase/firebase.utils";
|
||||
import {selectBodyshop} from "../user/user.selectors";
|
||||
import {techLoginFailure, techLoginSuccess} from "./tech.actions";
|
||||
import TechActionTypes from "./tech.types";
|
||||
|
||||
export function* onSignInStart() {
|
||||
yield takeLatest(TechActionTypes.TECH_LOGIN_START, signInStart);
|
||||
yield takeLatest(TechActionTypes.TECH_LOGIN_START, signInStart);
|
||||
}
|
||||
export function* signInStart({ payload: { employeeid, pin } }) {
|
||||
try {
|
||||
logImEXEvent("redux_tech_sign_in");
|
||||
|
||||
const bodyshop = yield select(selectBodyshop);
|
||||
const response = yield call(axios.post, "/tech/login", {
|
||||
shopid: bodyshop.id,
|
||||
employeeid: employeeid,
|
||||
pin: pin,
|
||||
});
|
||||
export function* signInStart({payload: {employeeid, pin}}) {
|
||||
try {
|
||||
logImEXEvent("redux_tech_sign_in");
|
||||
|
||||
const { valid, technician, error } = response.data;
|
||||
const bodyshop = yield select(selectBodyshop);
|
||||
const response = yield call(axios.post, "/tech/login", {
|
||||
shopid: bodyshop.id,
|
||||
employeeid: employeeid,
|
||||
pin: pin,
|
||||
});
|
||||
|
||||
if (valid) {
|
||||
yield put(techLoginSuccess(technician));
|
||||
} else {
|
||||
yield put(techLoginFailure(error));
|
||||
const {valid, technician, error} = response.data;
|
||||
|
||||
if (valid) {
|
||||
yield put(techLoginSuccess(technician));
|
||||
} else {
|
||||
yield put(techLoginFailure(error));
|
||||
}
|
||||
} catch (error) {
|
||||
yield put(techLoginFailure(error));
|
||||
}
|
||||
} catch (error) {
|
||||
yield put(techLoginFailure(error));
|
||||
}
|
||||
}
|
||||
|
||||
export function* techSagas() {
|
||||
yield all([call(onSignInStart)]);
|
||||
yield all([call(onSignInStart)]);
|
||||
}
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import { createSelector } from "reselect";
|
||||
import {createSelector} from "reselect";
|
||||
|
||||
const selectTechReducer = (state) => state.tech;
|
||||
|
||||
export const selectTechnician = createSelector(
|
||||
[selectTechReducer],
|
||||
(application) => application.technician
|
||||
[selectTechReducer],
|
||||
(application) => application.technician
|
||||
);
|
||||
export const selectLoginError = createSelector(
|
||||
[selectTechReducer],
|
||||
(application) => application.loginError
|
||||
[selectTechReducer],
|
||||
(application) => application.loginError
|
||||
);
|
||||
export const selectLoginLoading = createSelector(
|
||||
[selectTechReducer],
|
||||
(application) => application.loginLoading
|
||||
[selectTechReducer],
|
||||
(application) => application.loginLoading
|
||||
);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
const TechActionTypes = {
|
||||
TECH_LOGIN_START: "TECH_LOGIN_START",
|
||||
TECH_LOGIN_SUCCESS: "TECH_LOGIN_SUCCESS",
|
||||
TECH_LOGIN_FAILURE: "TECH_LOGIN_FAILURE",
|
||||
TECH_LOGOUT: "TECH_LOGOUT",
|
||||
TECH_LOGIN_START: "TECH_LOGIN_START",
|
||||
TECH_LOGIN_SUCCESS: "TECH_LOGIN_SUCCESS",
|
||||
TECH_LOGIN_FAILURE: "TECH_LOGIN_FAILURE",
|
||||
TECH_LOGOUT: "TECH_LOGOUT",
|
||||
};
|
||||
export default TechActionTypes;
|
||||
|
||||
@@ -1,121 +1,121 @@
|
||||
import UserActionTypes from "./user.types";
|
||||
|
||||
export const signInSuccess = (user) => ({
|
||||
type: UserActionTypes.SIGN_IN_SUCCESS,
|
||||
payload: user,
|
||||
type: UserActionTypes.SIGN_IN_SUCCESS,
|
||||
payload: user,
|
||||
});
|
||||
export const signInFailure = (errorMsg) => ({
|
||||
type: UserActionTypes.SIGN_IN_FAILURE,
|
||||
payload: errorMsg,
|
||||
type: UserActionTypes.SIGN_IN_FAILURE,
|
||||
payload: errorMsg,
|
||||
});
|
||||
|
||||
export const emailSignInStart = (emailAndPassword) => ({
|
||||
type: UserActionTypes.EMAIL_SIGN_IN_START,
|
||||
payload: emailAndPassword,
|
||||
type: UserActionTypes.EMAIL_SIGN_IN_START,
|
||||
payload: emailAndPassword,
|
||||
});
|
||||
|
||||
export const checkUserSession = () => ({
|
||||
type: UserActionTypes.CHECK_USER_SESSION,
|
||||
type: UserActionTypes.CHECK_USER_SESSION,
|
||||
});
|
||||
|
||||
export const signOutStart = () => ({
|
||||
type: UserActionTypes.SIGN_OUT_START,
|
||||
type: UserActionTypes.SIGN_OUT_START,
|
||||
});
|
||||
export const signOutSuccess = () => ({
|
||||
type: UserActionTypes.SIGN_OUT_SUCCESS,
|
||||
type: UserActionTypes.SIGN_OUT_SUCCESS,
|
||||
});
|
||||
|
||||
export const signOutFailure = (error) => ({
|
||||
type: UserActionTypes.SIGN_OUT_FAILURE,
|
||||
payload: error,
|
||||
type: UserActionTypes.SIGN_OUT_FAILURE,
|
||||
payload: error,
|
||||
});
|
||||
|
||||
export const unauthorizedUser = () => ({
|
||||
type: UserActionTypes.UNAUTHORIZED_USER,
|
||||
type: UserActionTypes.UNAUTHORIZED_USER,
|
||||
});
|
||||
|
||||
export const setUserLanguage = (language) => ({
|
||||
type: UserActionTypes.SET_USER_LANGUAGE,
|
||||
payload: language,
|
||||
type: UserActionTypes.SET_USER_LANGUAGE,
|
||||
payload: language,
|
||||
});
|
||||
|
||||
export const updateUserDetails = (userDetails) => ({
|
||||
type: UserActionTypes.UPDATE_USER_DETAILS,
|
||||
payload: userDetails,
|
||||
type: UserActionTypes.UPDATE_USER_DETAILS,
|
||||
payload: userDetails,
|
||||
});
|
||||
|
||||
export const updateUserDetailsSuccess = (userDetails) => ({
|
||||
type: UserActionTypes.UPDATE_USER_DETAILS_SUCCESS,
|
||||
payload: userDetails,
|
||||
type: UserActionTypes.UPDATE_USER_DETAILS_SUCCESS,
|
||||
payload: userDetails,
|
||||
});
|
||||
|
||||
export const setBodyshop = (bodyshop) => ({
|
||||
type: UserActionTypes.SET_SHOP_DETAILS,
|
||||
payload: bodyshop,
|
||||
type: UserActionTypes.SET_SHOP_DETAILS,
|
||||
payload: bodyshop,
|
||||
});
|
||||
|
||||
export const setInstanceId = (userInfo) => ({
|
||||
type: UserActionTypes.SET_INSTANCE_ID,
|
||||
payload: userInfo,
|
||||
type: UserActionTypes.SET_INSTANCE_ID,
|
||||
payload: userInfo,
|
||||
});
|
||||
|
||||
export const checkInstanceId = (uid) => ({
|
||||
type: UserActionTypes.CHECK_INSTANCE_ID,
|
||||
payload: uid,
|
||||
type: UserActionTypes.CHECK_INSTANCE_ID,
|
||||
payload: uid,
|
||||
});
|
||||
|
||||
export const setInstanceConflict = () => ({
|
||||
type: UserActionTypes.SET_INSTANCE_CONFLICT,
|
||||
type: UserActionTypes.SET_INSTANCE_CONFLICT,
|
||||
});
|
||||
|
||||
export const setLocalFingerprint = (fingerprint) => ({
|
||||
type: UserActionTypes.SET_LOCAL_FINGERPRINT,
|
||||
payload: fingerprint,
|
||||
type: UserActionTypes.SET_LOCAL_FINGERPRINT,
|
||||
payload: fingerprint,
|
||||
});
|
||||
|
||||
export const sendPasswordReset = (email) => ({
|
||||
type: UserActionTypes.SEND_PASSWORD_RESET_EMAIL_START,
|
||||
payload: email,
|
||||
type: UserActionTypes.SEND_PASSWORD_RESET_EMAIL_START,
|
||||
payload: email,
|
||||
});
|
||||
|
||||
export const sendPasswordResetAgain = (email) => ({
|
||||
type: UserActionTypes.SEND_PASSWORD_RESET_EMAIL_START_AGAIN,
|
||||
payload: email,
|
||||
type: UserActionTypes.SEND_PASSWORD_RESET_EMAIL_START_AGAIN,
|
||||
payload: email,
|
||||
});
|
||||
|
||||
export const sendPasswordResetFailure = (error) => ({
|
||||
type: UserActionTypes.SEND_PASSWORD_RESET_EMAIL_FAILURE,
|
||||
payload: error,
|
||||
type: UserActionTypes.SEND_PASSWORD_RESET_EMAIL_FAILURE,
|
||||
payload: error,
|
||||
});
|
||||
export const sendPasswordResetSuccess = () => ({
|
||||
type: UserActionTypes.SEND_PASSWORD_RESET_EMAIL_SUCCESS,
|
||||
type: UserActionTypes.SEND_PASSWORD_RESET_EMAIL_SUCCESS,
|
||||
});
|
||||
|
||||
export const validatePasswordResetStart = (emailAndPin) => ({
|
||||
type: UserActionTypes.VALIDATE_PASSWORD_RESET_START,
|
||||
payload: emailAndPin,
|
||||
type: UserActionTypes.VALIDATE_PASSWORD_RESET_START,
|
||||
payload: emailAndPin,
|
||||
});
|
||||
|
||||
export const validatePasswordResetSuccess = () => ({
|
||||
type: UserActionTypes.VALIDATE_PASSWORD_RESET_SUCCESS,
|
||||
type: UserActionTypes.VALIDATE_PASSWORD_RESET_SUCCESS,
|
||||
});
|
||||
|
||||
export const validatePasswordResetFailure = (error) => ({
|
||||
type: UserActionTypes.VALIDATE_PASSWORD_RESET_FAILURE,
|
||||
payload: error,
|
||||
type: UserActionTypes.VALIDATE_PASSWORD_RESET_FAILURE,
|
||||
payload: error,
|
||||
});
|
||||
|
||||
export const setAuthlevel = (authlevel) => ({
|
||||
type: UserActionTypes.SET_AUTH_LEVEL,
|
||||
payload: authlevel,
|
||||
type: UserActionTypes.SET_AUTH_LEVEL,
|
||||
payload: authlevel,
|
||||
});
|
||||
|
||||
export const setCurrentEula = (eula) => ({
|
||||
type: UserActionTypes.SET_CURRENT_EULA,
|
||||
payload: eula,
|
||||
type: UserActionTypes.SET_CURRENT_EULA,
|
||||
payload: eula,
|
||||
});
|
||||
|
||||
export const acceptEula = () => ({
|
||||
type: UserActionTypes.EULA_ACCEPTED,
|
||||
type: UserActionTypes.EULA_ACCEPTED,
|
||||
});
|
||||
|
||||
|
||||
@@ -1,129 +1,129 @@
|
||||
import UserActionTypes from "./user.types";
|
||||
|
||||
const INITIAL_STATE = {
|
||||
currentUser: {
|
||||
authorized: null,
|
||||
eulaIsAccepted: false,
|
||||
//language: "en-US"
|
||||
},
|
||||
bodyshop: null,
|
||||
loginLoading: false,
|
||||
fingerprint: null,
|
||||
error: null,
|
||||
conflict: false,
|
||||
passwordreset: {
|
||||
email: null,
|
||||
currentUser: {
|
||||
authorized: null,
|
||||
eulaIsAccepted: false,
|
||||
//language: "en-US"
|
||||
},
|
||||
bodyshop: null,
|
||||
loginLoading: false,
|
||||
fingerprint: null,
|
||||
error: null,
|
||||
success: false,
|
||||
loading: false,
|
||||
},
|
||||
authLevel: 0,
|
||||
currentEula: null,
|
||||
conflict: false,
|
||||
passwordreset: {
|
||||
email: null,
|
||||
error: null,
|
||||
success: false,
|
||||
loading: false,
|
||||
},
|
||||
authLevel: 0,
|
||||
currentEula: null,
|
||||
};
|
||||
|
||||
const userReducer = (state = INITIAL_STATE, action) => {
|
||||
switch (action.type) {
|
||||
case UserActionTypes.SET_LOCAL_FINGERPRINT:
|
||||
return { ...state, fingerprint: action.payload };
|
||||
case UserActionTypes.SET_INSTANCE_ID:
|
||||
return { ...state, conflict: false };
|
||||
case UserActionTypes.SET_INSTANCE_CONFLICT:
|
||||
return { ...state, conflict: true };
|
||||
case UserActionTypes.EMAIL_SIGN_IN_START:
|
||||
return { ...state, loginLoading: true };
|
||||
case UserActionTypes.VALIDATE_PASSWORD_RESET_START:
|
||||
case UserActionTypes.SEND_PASSWORD_RESET_EMAIL_START:
|
||||
return {
|
||||
...state,
|
||||
passwordreset: {
|
||||
email: action.payload,
|
||||
error: null,
|
||||
success: false,
|
||||
loading: true,
|
||||
},
|
||||
};
|
||||
case UserActionTypes.SEND_PASSWORD_RESET_EMAIL_START_AGAIN:
|
||||
return {
|
||||
...state,
|
||||
passwordreset: {
|
||||
email: action.payload,
|
||||
error: null,
|
||||
success: true,
|
||||
loading: true,
|
||||
},
|
||||
};
|
||||
case UserActionTypes.VALIDATE_PASSWORD_RESET_FAILURE:
|
||||
case UserActionTypes.SEND_PASSWORD_RESET_EMAIL_FAILURE:
|
||||
return { ...state, passwordreset: { error: action.payload } };
|
||||
case UserActionTypes.VALIDATE_PASSWORD_RESET_SUCCESS:
|
||||
case UserActionTypes.SEND_PASSWORD_RESET_EMAIL_SUCCESS:
|
||||
return {
|
||||
...state,
|
||||
passwordreset: {
|
||||
...state.passwordreset,
|
||||
success: true,
|
||||
loading: false,
|
||||
},
|
||||
};
|
||||
case UserActionTypes.EULA_ACCEPTED:
|
||||
return {
|
||||
...state,
|
||||
currentUser:{...state.currentUser, eulaIsAccepted: true},
|
||||
currentEula: null,
|
||||
};
|
||||
case UserActionTypes.SIGN_IN_SUCCESS:
|
||||
const{ currentEula,...currentUser} = action.payload
|
||||
return {
|
||||
...state,
|
||||
loginLoading: false,
|
||||
currentUser: currentUser,
|
||||
currentEula,
|
||||
error: null,
|
||||
};
|
||||
case UserActionTypes.SIGN_OUT_SUCCESS:
|
||||
return {
|
||||
...state,
|
||||
currentUser: { authorized: false },
|
||||
error: null,
|
||||
};
|
||||
case UserActionTypes.UNAUTHORIZED_USER:
|
||||
return {
|
||||
...state,
|
||||
error: null,
|
||||
currentUser: { authorized: false },
|
||||
};
|
||||
case UserActionTypes.SET_USER_LANGUAGE:
|
||||
return {
|
||||
...state,
|
||||
language: action.payload,
|
||||
};
|
||||
case UserActionTypes.UPDATE_USER_DETAILS_SUCCESS:
|
||||
return {
|
||||
...state,
|
||||
currentUser: {
|
||||
...state.currentUser,
|
||||
...action.payload, //Spread current user details in.
|
||||
},
|
||||
};
|
||||
switch (action.type) {
|
||||
case UserActionTypes.SET_LOCAL_FINGERPRINT:
|
||||
return {...state, fingerprint: action.payload};
|
||||
case UserActionTypes.SET_INSTANCE_ID:
|
||||
return {...state, conflict: false};
|
||||
case UserActionTypes.SET_INSTANCE_CONFLICT:
|
||||
return {...state, conflict: true};
|
||||
case UserActionTypes.EMAIL_SIGN_IN_START:
|
||||
return {...state, loginLoading: true};
|
||||
case UserActionTypes.VALIDATE_PASSWORD_RESET_START:
|
||||
case UserActionTypes.SEND_PASSWORD_RESET_EMAIL_START:
|
||||
return {
|
||||
...state,
|
||||
passwordreset: {
|
||||
email: action.payload,
|
||||
error: null,
|
||||
success: false,
|
||||
loading: true,
|
||||
},
|
||||
};
|
||||
case UserActionTypes.SEND_PASSWORD_RESET_EMAIL_START_AGAIN:
|
||||
return {
|
||||
...state,
|
||||
passwordreset: {
|
||||
email: action.payload,
|
||||
error: null,
|
||||
success: true,
|
||||
loading: true,
|
||||
},
|
||||
};
|
||||
case UserActionTypes.VALIDATE_PASSWORD_RESET_FAILURE:
|
||||
case UserActionTypes.SEND_PASSWORD_RESET_EMAIL_FAILURE:
|
||||
return {...state, passwordreset: {error: action.payload}};
|
||||
case UserActionTypes.VALIDATE_PASSWORD_RESET_SUCCESS:
|
||||
case UserActionTypes.SEND_PASSWORD_RESET_EMAIL_SUCCESS:
|
||||
return {
|
||||
...state,
|
||||
passwordreset: {
|
||||
...state.passwordreset,
|
||||
success: true,
|
||||
loading: false,
|
||||
},
|
||||
};
|
||||
case UserActionTypes.EULA_ACCEPTED:
|
||||
return {
|
||||
...state,
|
||||
currentUser: {...state.currentUser, eulaIsAccepted: true},
|
||||
currentEula: null,
|
||||
};
|
||||
case UserActionTypes.SIGN_IN_SUCCESS:
|
||||
const {currentEula, ...currentUser} = action.payload
|
||||
return {
|
||||
...state,
|
||||
loginLoading: false,
|
||||
currentUser: currentUser,
|
||||
currentEula,
|
||||
error: null,
|
||||
};
|
||||
case UserActionTypes.SIGN_OUT_SUCCESS:
|
||||
return {
|
||||
...state,
|
||||
currentUser: {authorized: false},
|
||||
error: null,
|
||||
};
|
||||
case UserActionTypes.UNAUTHORIZED_USER:
|
||||
return {
|
||||
...state,
|
||||
error: null,
|
||||
currentUser: {authorized: false},
|
||||
};
|
||||
case UserActionTypes.SET_USER_LANGUAGE:
|
||||
return {
|
||||
...state,
|
||||
language: action.payload,
|
||||
};
|
||||
case UserActionTypes.UPDATE_USER_DETAILS_SUCCESS:
|
||||
return {
|
||||
...state,
|
||||
currentUser: {
|
||||
...state.currentUser,
|
||||
...action.payload, //Spread current user details in.
|
||||
},
|
||||
};
|
||||
|
||||
case UserActionTypes.SET_SHOP_DETAILS:
|
||||
return {
|
||||
...state,
|
||||
bodyshop: action.payload,
|
||||
};
|
||||
case UserActionTypes.SIGN_IN_FAILURE:
|
||||
case UserActionTypes.SIGN_OUT_FAILURE:
|
||||
case UserActionTypes.EMAIL_SIGN_UP_FAILURE:
|
||||
return {
|
||||
...state,
|
||||
loginLoading: false,
|
||||
error: action.payload,
|
||||
};
|
||||
case UserActionTypes.SET_AUTH_LEVEL:
|
||||
return { ...state, authLevel: action.payload };
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
case UserActionTypes.SET_SHOP_DETAILS:
|
||||
return {
|
||||
...state,
|
||||
bodyshop: action.payload,
|
||||
};
|
||||
case UserActionTypes.SIGN_IN_FAILURE:
|
||||
case UserActionTypes.SIGN_OUT_FAILURE:
|
||||
case UserActionTypes.EMAIL_SIGN_UP_FAILURE:
|
||||
return {
|
||||
...state,
|
||||
loginLoading: false,
|
||||
error: action.payload,
|
||||
};
|
||||
case UserActionTypes.SET_AUTH_LEVEL:
|
||||
return {...state, authLevel: action.payload};
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
export default userReducer;
|
||||
|
||||
@@ -1,46 +1,46 @@
|
||||
import FingerprintJS from "@fingerprintjs/fingerprintjs";
|
||||
import * as Sentry from "@sentry/browser";
|
||||
import { notification } from "antd";
|
||||
import {notification} from "antd";
|
||||
import axios from "axios";
|
||||
import { setUserId, setUserProperties } from "firebase/analytics";
|
||||
import {setUserId, setUserProperties} from "firebase/analytics";
|
||||
import {
|
||||
checkActionCode,
|
||||
confirmPasswordReset,
|
||||
sendPasswordResetEmail,
|
||||
signInWithEmailAndPassword,
|
||||
signOut,
|
||||
checkActionCode,
|
||||
confirmPasswordReset,
|
||||
sendPasswordResetEmail,
|
||||
signInWithEmailAndPassword,
|
||||
signOut,
|
||||
} from "firebase/auth";
|
||||
import { doc, getDoc, setDoc } from "firebase/firestore";
|
||||
import { getToken } from "firebase/messaging";
|
||||
import {doc, getDoc, setDoc} from "firebase/firestore";
|
||||
import {getToken} from "firebase/messaging";
|
||||
import i18next from "i18next";
|
||||
import LogRocket from "logrocket";
|
||||
import { all, call, delay, put, select, takeLatest } from "redux-saga/effects";
|
||||
import { factory } from "../../App/App.container";
|
||||
import {all, call, delay, put, select, takeLatest} from "redux-saga/effects";
|
||||
import {factory} from "../../App/App.container";
|
||||
import {
|
||||
analytics,
|
||||
auth,
|
||||
firestore,
|
||||
getCurrentUser,
|
||||
logImEXEvent,
|
||||
messaging,
|
||||
updateCurrentUser,
|
||||
analytics,
|
||||
auth,
|
||||
firestore,
|
||||
getCurrentUser,
|
||||
logImEXEvent,
|
||||
messaging,
|
||||
updateCurrentUser,
|
||||
} from "../../firebase/firebase.utils";
|
||||
import {
|
||||
checkInstanceId,
|
||||
sendPasswordResetFailure,
|
||||
sendPasswordResetSuccess,
|
||||
setAuthlevel,
|
||||
setInstanceConflict,
|
||||
setInstanceId,
|
||||
setLocalFingerprint,
|
||||
signInFailure,
|
||||
signInSuccess,
|
||||
signOutFailure,
|
||||
signOutSuccess,
|
||||
unauthorizedUser,
|
||||
updateUserDetailsSuccess,
|
||||
validatePasswordResetFailure,
|
||||
validatePasswordResetSuccess,
|
||||
checkInstanceId,
|
||||
sendPasswordResetFailure,
|
||||
sendPasswordResetSuccess,
|
||||
setAuthlevel,
|
||||
setInstanceConflict,
|
||||
setInstanceId,
|
||||
setLocalFingerprint,
|
||||
signInFailure,
|
||||
signInSuccess,
|
||||
signOutFailure,
|
||||
signOutSuccess,
|
||||
unauthorizedUser,
|
||||
updateUserDetailsSuccess,
|
||||
validatePasswordResetFailure,
|
||||
validatePasswordResetSuccess,
|
||||
} from "./user.actions";
|
||||
import UserActionTypes from "./user.types";
|
||||
import client from "../../utils/GraphQLClient";
|
||||
@@ -50,289 +50,299 @@ import day from "../../utils/day";
|
||||
const fpPromise = FingerprintJS.load();
|
||||
|
||||
export function* onEmailSignInStart() {
|
||||
yield takeLatest(UserActionTypes.EMAIL_SIGN_IN_START, signInWithEmail);
|
||||
yield takeLatest(UserActionTypes.EMAIL_SIGN_IN_START, signInWithEmail);
|
||||
}
|
||||
export function* signInWithEmail({ payload: { email, password } }) {
|
||||
try {
|
||||
logImEXEvent("redux_sign_in_attempt", { user: email });
|
||||
|
||||
const { user } = yield signInWithEmailAndPassword(auth, email, password);
|
||||
export function* signInWithEmail({payload: {email, password}}) {
|
||||
try {
|
||||
logImEXEvent("redux_sign_in_attempt", {user: email});
|
||||
|
||||
yield put(
|
||||
signInSuccess({
|
||||
uid: user.uid,
|
||||
email: user.email,
|
||||
displayName: user.displayName,
|
||||
photoURL: user.photoURL,
|
||||
authorized: true,
|
||||
})
|
||||
);
|
||||
} catch (error) {
|
||||
yield put(signInFailure(error));
|
||||
logImEXEvent("redux_sign_in_failure", { user: email, error });
|
||||
}
|
||||
const {user} = yield signInWithEmailAndPassword(auth, email, password);
|
||||
|
||||
yield put(
|
||||
signInSuccess({
|
||||
uid: user.uid,
|
||||
email: user.email,
|
||||
displayName: user.displayName,
|
||||
photoURL: user.photoURL,
|
||||
authorized: true,
|
||||
})
|
||||
);
|
||||
} catch (error) {
|
||||
yield put(signInFailure(error));
|
||||
logImEXEvent("redux_sign_in_failure", {user: email, error});
|
||||
}
|
||||
}
|
||||
|
||||
export function* onCheckUserSession() {
|
||||
yield takeLatest(UserActionTypes.CHECK_USER_SESSION, isUserAuthenticated);
|
||||
yield takeLatest(UserActionTypes.CHECK_USER_SESSION, isUserAuthenticated);
|
||||
}
|
||||
|
||||
|
||||
export function* isUserAuthenticated() {
|
||||
try {
|
||||
logImEXEvent("redux_auth_check");
|
||||
|
||||
const user = yield getCurrentUser();
|
||||
if (!user) {
|
||||
yield put(unauthorizedUser());
|
||||
return;
|
||||
}
|
||||
|
||||
LogRocket.identify(user.email);
|
||||
|
||||
const eulaQuery = yield client.query({
|
||||
query: QUERY_EULA,
|
||||
variables: {
|
||||
now: day()
|
||||
},
|
||||
});
|
||||
|
||||
const eulaIsAccepted = eulaQuery.data.eulas.length > 0 && eulaQuery.data.eulas[0].eula_acceptances.length > 0;
|
||||
|
||||
yield put(
|
||||
signInSuccess({
|
||||
uid: user.uid,
|
||||
email: user.email,
|
||||
displayName: user.displayName,
|
||||
photoURL: user.photoURL,
|
||||
authorized: true,
|
||||
eulaIsAccepted,
|
||||
currentEula: eulaIsAccepted ? null : eulaQuery.data.eulas[0],
|
||||
})
|
||||
);
|
||||
} catch (error) {
|
||||
yield put(signInFailure(error));
|
||||
}
|
||||
}
|
||||
export function* onSignOutStart() {
|
||||
yield takeLatest(UserActionTypes.SIGN_OUT_START, signOutStart);
|
||||
}
|
||||
export function* signOutStart() {
|
||||
try {
|
||||
logImEXEvent("redux_sign_out");
|
||||
|
||||
const state = yield select();
|
||||
|
||||
//unsub from topic.
|
||||
|
||||
try {
|
||||
const fcm_tokens = yield getToken(messaging);
|
||||
yield call(axios.post, "/notifications/unsubscribe", {
|
||||
fcm_tokens,
|
||||
imexshopid: state.user.bodyshop.imexshopid,
|
||||
type: "messaging",
|
||||
});
|
||||
} catch (error) {
|
||||
console.log("No FCM token. Skipping unsubscribe.");
|
||||
}
|
||||
logImEXEvent("redux_auth_check");
|
||||
|
||||
yield signOut(auth);
|
||||
yield put(signOutSuccess());
|
||||
localStorage.removeItem("token");
|
||||
} catch (error) {
|
||||
yield put(signOutFailure(error.message));
|
||||
}
|
||||
const user = yield getCurrentUser();
|
||||
if (!user) {
|
||||
yield put(unauthorizedUser());
|
||||
return;
|
||||
}
|
||||
|
||||
LogRocket.identify(user.email);
|
||||
|
||||
const eulaQuery = yield client.query({
|
||||
query: QUERY_EULA,
|
||||
variables: {
|
||||
now: day()
|
||||
},
|
||||
});
|
||||
|
||||
const eulaIsAccepted = eulaQuery.data.eulas.length > 0 && eulaQuery.data.eulas[0].eula_acceptances.length > 0;
|
||||
|
||||
yield put(
|
||||
signInSuccess({
|
||||
uid: user.uid,
|
||||
email: user.email,
|
||||
displayName: user.displayName,
|
||||
photoURL: user.photoURL,
|
||||
authorized: true,
|
||||
eulaIsAccepted,
|
||||
currentEula: eulaIsAccepted ? null : eulaQuery.data.eulas[0],
|
||||
})
|
||||
);
|
||||
} catch (error) {
|
||||
yield put(signInFailure(error));
|
||||
}
|
||||
}
|
||||
|
||||
export function* onSignOutStart() {
|
||||
yield takeLatest(UserActionTypes.SIGN_OUT_START, signOutStart);
|
||||
}
|
||||
|
||||
export function* signOutStart() {
|
||||
try {
|
||||
logImEXEvent("redux_sign_out");
|
||||
|
||||
const state = yield select();
|
||||
|
||||
//unsub from topic.
|
||||
|
||||
try {
|
||||
const fcm_tokens = yield getToken(messaging);
|
||||
yield call(axios.post, "/notifications/unsubscribe", {
|
||||
fcm_tokens,
|
||||
imexshopid: state.user.bodyshop.imexshopid,
|
||||
type: "messaging",
|
||||
});
|
||||
} catch (error) {
|
||||
console.log("No FCM token. Skipping unsubscribe.");
|
||||
}
|
||||
|
||||
yield signOut(auth);
|
||||
yield put(signOutSuccess());
|
||||
localStorage.removeItem("token");
|
||||
} catch (error) {
|
||||
yield put(signOutFailure(error.message));
|
||||
}
|
||||
}
|
||||
|
||||
export function* onUpdateUserDetails() {
|
||||
yield takeLatest(UserActionTypes.UPDATE_USER_DETAILS, updateUserDetails);
|
||||
yield takeLatest(UserActionTypes.UPDATE_USER_DETAILS, updateUserDetails);
|
||||
}
|
||||
|
||||
export function* updateUserDetails(userDetails) {
|
||||
try {
|
||||
const updatedDetails = yield updateCurrentUser(userDetails.payload);
|
||||
try {
|
||||
const updatedDetails = yield updateCurrentUser(userDetails.payload);
|
||||
|
||||
yield put(updateUserDetailsSuccess(updatedDetails));
|
||||
notification.open({
|
||||
type: "success",
|
||||
message: i18next.t("profile.successes.updated"),
|
||||
});
|
||||
} catch (error) {
|
||||
//yield put(signOutFailure(error.message));
|
||||
}
|
||||
yield put(updateUserDetailsSuccess(updatedDetails));
|
||||
notification.open({
|
||||
type: "success",
|
||||
message: i18next.t("profile.successes.updated"),
|
||||
});
|
||||
} catch (error) {
|
||||
//yield put(signOutFailure(error.message));
|
||||
}
|
||||
}
|
||||
|
||||
export function* onSetInstanceId() {
|
||||
yield takeLatest(UserActionTypes.SET_INSTANCE_ID, setInstanceIdSaga);
|
||||
yield takeLatest(UserActionTypes.SET_INSTANCE_ID, setInstanceIdSaga);
|
||||
}
|
||||
export function* setInstanceIdSaga({ payload: uid }) {
|
||||
try {
|
||||
const userInstanceRef = doc(firestore, `userInstance/${uid}`);
|
||||
|
||||
// Get the visitor identifier when you need it.
|
||||
const fp = yield fpPromise;
|
||||
const result = yield fp.get();
|
||||
yield setDoc(userInstanceRef, {
|
||||
timestamp: new Date(),
|
||||
fingerprint: result.visitorId,
|
||||
});
|
||||
export function* setInstanceIdSaga({payload: uid}) {
|
||||
try {
|
||||
const userInstanceRef = doc(firestore, `userInstance/${uid}`);
|
||||
|
||||
yield put(setLocalFingerprint(result.visitorId));
|
||||
yield delay(5 * 60 * 1000);
|
||||
if (process.env.NODE_ENV === "production") yield put(checkInstanceId(uid));
|
||||
} catch (error) {
|
||||
console.log("error", error);
|
||||
}
|
||||
// Get the visitor identifier when you need it.
|
||||
const fp = yield fpPromise;
|
||||
const result = yield fp.get();
|
||||
yield setDoc(userInstanceRef, {
|
||||
timestamp: new Date(),
|
||||
fingerprint: result.visitorId,
|
||||
});
|
||||
|
||||
yield put(setLocalFingerprint(result.visitorId));
|
||||
yield delay(5 * 60 * 1000);
|
||||
if (process.env.NODE_ENV === "production") yield put(checkInstanceId(uid));
|
||||
} catch (error) {
|
||||
console.log("error", error);
|
||||
}
|
||||
}
|
||||
|
||||
export function* onCheckInstanceId() {
|
||||
yield takeLatest(UserActionTypes.CHECK_INSTANCE_ID, checkInstanceIdSaga);
|
||||
yield takeLatest(UserActionTypes.CHECK_INSTANCE_ID, checkInstanceIdSaga);
|
||||
}
|
||||
export function* checkInstanceIdSaga({ payload: uid }) {
|
||||
try {
|
||||
const snapshot = yield getDoc(doc(firestore, `userInstance/${uid}`));
|
||||
let fingerprint = yield select((state) => state.user.fingerprint);
|
||||
yield put(setInstanceConflict());
|
||||
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());
|
||||
|
||||
export function* checkInstanceIdSaga({payload: uid}) {
|
||||
try {
|
||||
const snapshot = yield getDoc(doc(firestore, `userInstance/${uid}`));
|
||||
let fingerprint = yield select((state) => state.user.fingerprint);
|
||||
yield put(setInstanceConflict());
|
||||
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);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("error", error);
|
||||
}
|
||||
}
|
||||
|
||||
export function* onSignInSuccess() {
|
||||
yield takeLatest(UserActionTypes.SIGN_IN_SUCCESS, signInSuccessSaga);
|
||||
yield takeLatest(UserActionTypes.SIGN_IN_SUCCESS, signInSuccessSaga);
|
||||
}
|
||||
|
||||
export function* signInSuccessSaga({ payload }) {
|
||||
LogRocket.identify(payload.email);
|
||||
export function* signInSuccessSaga({payload}) {
|
||||
LogRocket.identify(payload.email);
|
||||
|
||||
try {
|
||||
// window.$crisp.push([
|
||||
// "set",
|
||||
// "user:nickname",
|
||||
// [payload.displayName || payload.email],
|
||||
// ]);
|
||||
try {
|
||||
// window.$crisp.push([
|
||||
// "set",
|
||||
// "user:nickname",
|
||||
// [payload.displayName || payload.email],
|
||||
// ]);
|
||||
|
||||
// window.$crisp.push(["set", "session:segments", [["rome-user"]]]);
|
||||
// window.$crisp.push(["set", "session:segments", [["rome-user"]]]);
|
||||
|
||||
Sentry.setUser({
|
||||
email: payload.email,
|
||||
username: payload.displayName || payload.email,
|
||||
});
|
||||
} catch (error) {
|
||||
console.log("Error updating Crisp settings.", error);
|
||||
}
|
||||
Sentry.setUser({
|
||||
email: payload.email,
|
||||
username: payload.displayName || payload.email,
|
||||
});
|
||||
} catch (error) {
|
||||
console.log("Error updating Crisp settings.", error);
|
||||
}
|
||||
|
||||
setUserId(analytics, payload.email);
|
||||
setUserProperties(analytics, payload);
|
||||
yield logImEXEvent("redux_sign_in_success");
|
||||
setUserId(analytics, payload.email);
|
||||
setUserProperties(analytics, payload);
|
||||
yield logImEXEvent("redux_sign_in_success");
|
||||
}
|
||||
|
||||
export function* onSendPasswordResetStart() {
|
||||
yield takeLatest(
|
||||
UserActionTypes.SEND_PASSWORD_RESET_EMAIL_START,
|
||||
sendPasswordResetEmailSaga
|
||||
);
|
||||
yield takeLatest(
|
||||
UserActionTypes.SEND_PASSWORD_RESET_EMAIL_START_AGAIN,
|
||||
sendPasswordResetEmailSaga
|
||||
);
|
||||
yield takeLatest(
|
||||
UserActionTypes.SEND_PASSWORD_RESET_EMAIL_START,
|
||||
sendPasswordResetEmailSaga
|
||||
);
|
||||
yield takeLatest(
|
||||
UserActionTypes.SEND_PASSWORD_RESET_EMAIL_START_AGAIN,
|
||||
sendPasswordResetEmailSaga
|
||||
);
|
||||
}
|
||||
export function* sendPasswordResetEmailSaga({ payload }) {
|
||||
try {
|
||||
yield sendPasswordResetEmail(auth, payload, {
|
||||
url: "https://romeonline.io/passwordreset",
|
||||
});
|
||||
|
||||
yield put(sendPasswordResetSuccess());
|
||||
} catch (error) {
|
||||
yield put(sendPasswordResetFailure(error.message));
|
||||
}
|
||||
export function* sendPasswordResetEmailSaga({payload}) {
|
||||
try {
|
||||
yield sendPasswordResetEmail(auth, payload, {
|
||||
url: "https://romeonline.io/passwordreset",
|
||||
});
|
||||
|
||||
yield put(sendPasswordResetSuccess());
|
||||
} catch (error) {
|
||||
yield put(sendPasswordResetFailure(error.message));
|
||||
}
|
||||
}
|
||||
|
||||
export function* onValidatePasswordResetStart() {
|
||||
yield takeLatest(
|
||||
UserActionTypes.VALIDATE_PASSWORD_RESET_START,
|
||||
validatePasswordResetStart
|
||||
);
|
||||
yield takeLatest(
|
||||
UserActionTypes.VALIDATE_PASSWORD_RESET_START,
|
||||
validatePasswordResetStart
|
||||
);
|
||||
}
|
||||
export function* validatePasswordResetStart({ payload: { password, code } }) {
|
||||
try {
|
||||
checkActionCode(auth, code);
|
||||
yield confirmPasswordReset(auth, code, password);
|
||||
yield put(validatePasswordResetSuccess());
|
||||
} catch (error) {
|
||||
yield put(validatePasswordResetFailure(error.message));
|
||||
}
|
||||
|
||||
export function* validatePasswordResetStart({payload: {password, code}}) {
|
||||
try {
|
||||
checkActionCode(auth, code);
|
||||
yield confirmPasswordReset(auth, code, password);
|
||||
yield put(validatePasswordResetSuccess());
|
||||
} catch (error) {
|
||||
yield put(validatePasswordResetFailure(error.message));
|
||||
}
|
||||
}
|
||||
|
||||
export function* onSetShopDetails() {
|
||||
yield takeLatest(
|
||||
UserActionTypes.SET_SHOP_DETAILS,
|
||||
SetAuthLevelFromShopDetails
|
||||
);
|
||||
yield takeLatest(
|
||||
UserActionTypes.SET_SHOP_DETAILS,
|
||||
SetAuthLevelFromShopDetails
|
||||
);
|
||||
}
|
||||
export function* SetAuthLevelFromShopDetails({ payload }) {
|
||||
try {
|
||||
const userEmail = yield select((state) => state.user.currentUser.email);
|
||||
|
||||
export function* SetAuthLevelFromShopDetails({payload}) {
|
||||
try {
|
||||
//console.log("Setting shop timezone.");
|
||||
// dayjs.tz.setDefault(payload.timezone);
|
||||
const userEmail = yield select((state) => state.user.currentUser.email);
|
||||
try {
|
||||
//console.log("Setting shop timezone.");
|
||||
// dayjs.tz.setDefault(payload.timezone);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
|
||||
factory.client(payload.imexshopid);
|
||||
|
||||
const authRecord = payload.associations.filter(
|
||||
(a) => a.useremail.toLowerCase() === userEmail.toLowerCase()
|
||||
);
|
||||
|
||||
yield put(setAuthlevel(authRecord[0] ? authRecord[0].authlevel : 0));
|
||||
yield put(
|
||||
updateUserDetailsSuccess(
|
||||
authRecord[0]
|
||||
? {validemail: authRecord[0].user.validemail}
|
||||
: {validemail: false}
|
||||
)
|
||||
);
|
||||
|
||||
if (payload.features.singleDeviceOnly) {
|
||||
const user = yield select((state) => state.user.currentUser);
|
||||
|
||||
if (!(user.email.includes("@imex.") || user.email.includes("@rome.")))
|
||||
yield put(setInstanceId(user.uid));
|
||||
}
|
||||
|
||||
try {
|
||||
// window.$crisp.push(["set", "user:company", [payload.shopname]]);
|
||||
// if (authRecord[0] && authRecord[0].user.validemail) {
|
||||
// window.$crisp.push(["set", "user:email", [authRecord[0].user.email]]);
|
||||
// }
|
||||
} catch (error) {
|
||||
console.error("Couldnt find $crisp.");
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
yield put(signInFailure(error.message));
|
||||
}
|
||||
|
||||
factory.client(payload.imexshopid);
|
||||
|
||||
const authRecord = payload.associations.filter(
|
||||
(a) => a.useremail.toLowerCase() === userEmail.toLowerCase()
|
||||
);
|
||||
|
||||
yield put(setAuthlevel(authRecord[0] ? authRecord[0].authlevel : 0));
|
||||
yield put(
|
||||
updateUserDetailsSuccess(
|
||||
authRecord[0]
|
||||
? { validemail: authRecord[0].user.validemail }
|
||||
: { validemail: false }
|
||||
)
|
||||
);
|
||||
|
||||
if (payload.features.singleDeviceOnly) {
|
||||
const user = yield select((state) => state.user.currentUser);
|
||||
|
||||
if (!(user.email.includes("@imex.") || user.email.includes("@rome.")))
|
||||
yield put(setInstanceId(user.uid));
|
||||
}
|
||||
|
||||
try {
|
||||
// window.$crisp.push(["set", "user:company", [payload.shopname]]);
|
||||
// if (authRecord[0] && authRecord[0].user.validemail) {
|
||||
// window.$crisp.push(["set", "user:email", [authRecord[0].user.email]]);
|
||||
// }
|
||||
} catch (error) {
|
||||
console.error("Couldnt find $crisp.");
|
||||
}
|
||||
} 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),
|
||||
]);
|
||||
yield all([
|
||||
call(onEmailSignInStart),
|
||||
call(onCheckUserSession),
|
||||
call(onSignOutStart),
|
||||
call(onUpdateUserDetails),
|
||||
call(onSetInstanceId),
|
||||
call(onCheckInstanceId),
|
||||
call(onSignInSuccess),
|
||||
call(onSendPasswordResetStart),
|
||||
call(onValidatePasswordResetStart),
|
||||
call(onSetShopDetails),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -1,40 +1,40 @@
|
||||
import { createSelector } from "reselect";
|
||||
import {createSelector} from "reselect";
|
||||
|
||||
const selectUser = (state) => state.user;
|
||||
|
||||
export const selectCurrentUser = createSelector(
|
||||
[selectUser],
|
||||
(user) => user.currentUser
|
||||
[selectUser],
|
||||
(user) => user.currentUser
|
||||
);
|
||||
|
||||
export const selectSignInError = createSelector(
|
||||
[selectUser],
|
||||
(user) => user.error
|
||||
[selectUser],
|
||||
(user) => user.error
|
||||
);
|
||||
|
||||
export const selectBodyshop = createSelector(
|
||||
[selectUser],
|
||||
(user) => user.bodyshop
|
||||
[selectUser],
|
||||
(user) => user.bodyshop
|
||||
);
|
||||
|
||||
export const selectInstanceConflict = createSelector(
|
||||
[selectUser],
|
||||
(user) => user.conflict
|
||||
[selectUser],
|
||||
(user) => user.conflict
|
||||
);
|
||||
|
||||
export const selectPasswordReset = createSelector(
|
||||
[selectUser],
|
||||
(user) => user.passwordreset
|
||||
[selectUser],
|
||||
(user) => user.passwordreset
|
||||
);
|
||||
|
||||
export const selectAuthLevel = createSelector(
|
||||
[selectUser],
|
||||
(user) => user.authLevel
|
||||
[selectUser],
|
||||
(user) => user.authLevel
|
||||
);
|
||||
|
||||
export const selectLoginLoading = createSelector(
|
||||
[selectUser],
|
||||
(user) => user.loginLoading
|
||||
[selectUser],
|
||||
(user) => user.loginLoading
|
||||
);
|
||||
|
||||
export const selectCurrentEula = createSelector(
|
||||
|
||||
@@ -1,38 +1,38 @@
|
||||
const UserActionTypes = {
|
||||
SET_CURRENT_USER: "SET_CURRENT_USER",
|
||||
GOOGLE_SIGN_IN_START: "GOOGLE_SIGN_IN_START",
|
||||
SIGN_IN_SUCCESS: "SIGN_IN_SUCCESS",
|
||||
SIGN_IN_FAILURE: "SIGN_IN_FAILURE",
|
||||
EMAIL_SIGN_IN_START: "EMAIL_SIGN_IN_START",
|
||||
CHECK_USER_SESSION: "CHECK_USER_SESSION",
|
||||
SIGN_OUT_START: "SIGN_OUT_START",
|
||||
SIGN_OUT_SUCCESS: "SIGN_OUT_SUCCESS",
|
||||
SIGN_OUT_FAILURE: "SIGN_OUT_FAILURE",
|
||||
EMAIL_SIGN_UP_START: "EMAIL_SIGN_UP_START",
|
||||
EMAIL_SIGN_UP_SUCCESS: "EMAIL_SIGN_UP_SUCCESS",
|
||||
EMAIL_SIGN_UP_FAILURE: "EMAIL_SIGN_UP_FAILURE",
|
||||
UNAUTHORIZED_USER: "UNAUTHORIZED_USER",
|
||||
SET_USER_LANGUAGE: "SET_USER_LANGUAGE",
|
||||
UPDATE_USER_DETAILS: "UPDATE_USER_DETAILS",
|
||||
UPDATE_USER_DETAILS_SUCCESS: "UPDATE_USER_DETAILS_SUCCESS",
|
||||
SET_SHOP_DETAILS: "SET_SHOP_DETAILS",
|
||||
SET_INSTANCE_ID: "SET_INSTANCE_ID",
|
||||
CHECK_INSTANCE_ID: "CHECK_INSTANCE_ID",
|
||||
SET_INSTANCE_CONFLICT: "SET_INSTANCE_CONFLICT",
|
||||
SET_LOCAL_FINGERPRINT: "SET_LOCAL_FINGERPRINT",
|
||||
SEND_PASSWORD_RESET_EMAIL_START: "SEND_PASSWORD_RESET_EMAIL_START",
|
||||
SEND_PASSWORD_RESET_EMAIL_START_AGAIN:
|
||||
"SEND_PASSWORD_RESET_EMAIL_START_AGAIN",
|
||||
SEND_PASSWORD_RESET_EMAIL_FAILURE: "SEND_PASSWORD_RESET_EMAIL_FAILURE",
|
||||
SEND_PASSWORD_RESET_EMAIL_SUCCESS: "SEND_PASSWORD_RESET_EMAIL_SUCCESS",
|
||||
VALIDATE_PASSWORD_RESET_START: "VALIDATE_PASSWORD_RESET_START",
|
||||
VALIDATE_PASSWORD_RESET_SUCCESS: "VALIDATE_PASSWORD_RESET_SUCCESS",
|
||||
VALIDATE_PASSWORD_RESET_FAILURE: "VALIDATE_PASSWORD_RESET_FAILURE",
|
||||
SET_AUTH_LEVEL: "SET_AUTH_LEVEL",
|
||||
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_CURRENT_EULA: "SET_CURRENT_EULA",
|
||||
EULA_ACCEPTED : "EULA_ACCEPTED",
|
||||
SET_CURRENT_USER: "SET_CURRENT_USER",
|
||||
GOOGLE_SIGN_IN_START: "GOOGLE_SIGN_IN_START",
|
||||
SIGN_IN_SUCCESS: "SIGN_IN_SUCCESS",
|
||||
SIGN_IN_FAILURE: "SIGN_IN_FAILURE",
|
||||
EMAIL_SIGN_IN_START: "EMAIL_SIGN_IN_START",
|
||||
CHECK_USER_SESSION: "CHECK_USER_SESSION",
|
||||
SIGN_OUT_START: "SIGN_OUT_START",
|
||||
SIGN_OUT_SUCCESS: "SIGN_OUT_SUCCESS",
|
||||
SIGN_OUT_FAILURE: "SIGN_OUT_FAILURE",
|
||||
EMAIL_SIGN_UP_START: "EMAIL_SIGN_UP_START",
|
||||
EMAIL_SIGN_UP_SUCCESS: "EMAIL_SIGN_UP_SUCCESS",
|
||||
EMAIL_SIGN_UP_FAILURE: "EMAIL_SIGN_UP_FAILURE",
|
||||
UNAUTHORIZED_USER: "UNAUTHORIZED_USER",
|
||||
SET_USER_LANGUAGE: "SET_USER_LANGUAGE",
|
||||
UPDATE_USER_DETAILS: "UPDATE_USER_DETAILS",
|
||||
UPDATE_USER_DETAILS_SUCCESS: "UPDATE_USER_DETAILS_SUCCESS",
|
||||
SET_SHOP_DETAILS: "SET_SHOP_DETAILS",
|
||||
SET_INSTANCE_ID: "SET_INSTANCE_ID",
|
||||
CHECK_INSTANCE_ID: "CHECK_INSTANCE_ID",
|
||||
SET_INSTANCE_CONFLICT: "SET_INSTANCE_CONFLICT",
|
||||
SET_LOCAL_FINGERPRINT: "SET_LOCAL_FINGERPRINT",
|
||||
SEND_PASSWORD_RESET_EMAIL_START: "SEND_PASSWORD_RESET_EMAIL_START",
|
||||
SEND_PASSWORD_RESET_EMAIL_START_AGAIN:
|
||||
"SEND_PASSWORD_RESET_EMAIL_START_AGAIN",
|
||||
SEND_PASSWORD_RESET_EMAIL_FAILURE: "SEND_PASSWORD_RESET_EMAIL_FAILURE",
|
||||
SEND_PASSWORD_RESET_EMAIL_SUCCESS: "SEND_PASSWORD_RESET_EMAIL_SUCCESS",
|
||||
VALIDATE_PASSWORD_RESET_START: "VALIDATE_PASSWORD_RESET_START",
|
||||
VALIDATE_PASSWORD_RESET_SUCCESS: "VALIDATE_PASSWORD_RESET_SUCCESS",
|
||||
VALIDATE_PASSWORD_RESET_FAILURE: "VALIDATE_PASSWORD_RESET_FAILURE",
|
||||
SET_AUTH_LEVEL: "SET_AUTH_LEVEL",
|
||||
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_CURRENT_EULA: "SET_CURRENT_EULA",
|
||||
EULA_ACCEPTED: "EULA_ACCEPTED",
|
||||
};
|
||||
export default UserActionTypes;
|
||||
|
||||
Reference in New Issue
Block a user