Added react icons. Additional work on Job tombstone page.

This commit is contained in:
Patrick Fic
2020-01-02 11:33:08 -08:00
parent 8969108cc4
commit b72665fc81
12 changed files with 105 additions and 45 deletions

View File

@@ -18,6 +18,7 @@
"react-apollo": "^3.1.3", "react-apollo": "^3.1.3",
"react-dom": "^16.12.0", "react-dom": "^16.12.0",
"react-i18next": "^11.2.7", "react-i18next": "^11.2.7",
"react-icons": "^3.8.0",
"react-moment": "^0.9.7", "react-moment": "^0.9.7",
"react-number-format": "^4.3.1", "react-number-format": "^4.3.1",
"react-router-dom": "^5.1.2", "react-router-dom": "^5.1.2",

View File

@@ -72,7 +72,6 @@ class AppContainer extends Component {
const token = localStorage.getItem("token"); const token = localStorage.getItem("token");
// return the headers to the context so httpLink can read them // return the headers to the context so httpLink can read them
if (token) { if (token) {
console.log("checking if token should refresh.");
if (shouldRefreshToken) { if (shouldRefreshToken) {
refreshToken(); refreshToken();
} }

View File

@@ -94,15 +94,15 @@ export default () => {
<div> <div>
<Switch> <Switch>
<ErrorBoundary> <ErrorBoundary>
<Suspense fallback={<div>Suspended Loading...</div>}> <Suspense fallback={<div>TODO: Suspense Loading</div>}>
<Route exact path="/" component={LandingPage} /> <Route exact path='/' component={LandingPage} />
<Route exact path="/unauthorized" component={Unauthorized} /> <Route exact path='/unauthorized' component={Unauthorized} />
<Route <Route
exact exact
path="/signin" path='/signin'
render={() => render={() =>
HookCurrentUser.data.currentUser ? ( HookCurrentUser.data.currentUser ? (
<Redirect to="/manage" /> <Redirect to='/manage' />
) : ( ) : (
<SignInPage /> <SignInPage />
) )
@@ -110,7 +110,7 @@ export default () => {
/> />
<PrivateRoute <PrivateRoute
isAuthorized={HookCurrentUser.data.currentUser ? true : false} isAuthorized={HookCurrentUser.data.currentUser ? true : false}
path="/manage" path='/manage'
component={ManagePage} component={ManagePage}
/> />
</Suspense> </Suspense>

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M23.5 7c.276 0 .5.224.5.5v.511c0 .793-.926.989-1.616.989l-1.086-2h2.202zm-1.441 3.506c.639 1.186.946 2.252.946 3.666 0 1.37-.397 2.533-1.005 3.981v1.847c0 .552-.448 1-1 1h-1.5c-.552 0-1-.448-1-1v-1h-13v1c0 .552-.448 1-1 1h-1.5c-.552 0-1-.448-1-1v-1.847c-.608-1.448-1.005-2.611-1.005-3.981 0-1.414.307-2.48.946-3.666.829-1.537 1.851-3.453 2.93-5.252.828-1.382 1.262-1.707 2.278-1.889 1.532-.275 2.918-.365 4.851-.365s3.319.09 4.851.365c1.016.182 1.45.507 2.278 1.889 1.079 1.799 2.101 3.715 2.93 5.252zm-16.059 2.994c0-.828-.672-1.5-1.5-1.5s-1.5.672-1.5 1.5.672 1.5 1.5 1.5 1.5-.672 1.5-1.5zm10 1c0-.276-.224-.5-.5-.5h-7c-.276 0-.5.224-.5.5s.224.5.5.5h7c.276 0 .5-.224.5-.5zm2.941-5.527s-.74-1.826-1.631-3.142c-.202-.298-.515-.502-.869-.566-1.511-.272-2.835-.359-4.441-.359s-2.93.087-4.441.359c-.354.063-.667.267-.869.566-.891 1.315-1.631 3.142-1.631 3.142 1.64.313 4.309.497 6.941.497s5.301-.184 6.941-.497zm2.059 4.527c0-.828-.672-1.5-1.5-1.5s-1.5.672-1.5 1.5.672 1.5 1.5 1.5 1.5-.672 1.5-1.5zm-18.298-6.5h-2.202c-.276 0-.5.224-.5.5v.511c0 .793.926.989 1.616.989l1.086-2z"/></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -1,4 +1,5 @@
import React, { useState } from "react"; import React, { useState } from "react";
import { Link } from "react-router-dom";
import AlertComponent from "../alert/alert.component"; import AlertComponent from "../alert/alert.component";
import { import {
Form, Form,
@@ -9,12 +10,15 @@ import {
Typography, Typography,
PageHeader, PageHeader,
Descriptions, Descriptions,
Tag Tag,
notification,
Avatar
} from "antd"; } from "antd";
import { UPDATE_JOB } from "../../graphql/jobs.queries"; import { UPDATE_JOB } from "../../graphql/jobs.queries";
import { useMutation } from "@apollo/react-hooks"; import { useMutation } from "@apollo/react-hooks";
import FormItemPhone from "../form-items-formatted/phone-form-item.component"; import FormItemPhone from "../form-items-formatted/phone-form-item.component";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import CarImage from "../../assets/car.svg";
const formItemLayout = { const formItemLayout = {
labelCol: { labelCol: {
@@ -33,22 +37,27 @@ function JobTombstone({ job, ...otherProps }) {
const { t } = useTranslation(); const { t } = useTranslation();
if (!job) { if (!job) {
return ( return <AlertComponent message={t("jobs.errors.noaccess")} type='error' />;
<AlertComponent
message='This job does not exist or you do not have access to it.'
type='error'
/>
);
} }
const handleSubmit = e => { const handleSubmit = e => {
e.preventDefault(); e.preventDefault();
otherProps.form.validateFieldsAndScroll((err, values) => { otherProps.form.validateFieldsAndScroll((err, values) => {
if (err) {
notification["error"]({
message: t("jobs.errors.validationtitle"),
description: t("jobs.errors.validation")
});
}
if (!err) { if (!err) {
mutationUpdateJob({ mutationUpdateJob({
variables: { jobId: jobContext.id, job: values } variables: { jobId: jobContext.id, job: values }
}).then(r => console.log("result", r)); }).then(r =>
notification["success"]({
message: t("jobs.successes.savetitle")
})
);
} }
}); });
}; };
@@ -59,13 +68,21 @@ function JobTombstone({ job, ...otherProps }) {
}; };
const { getFieldDecorator } = otherProps.form; const { getFieldDecorator } = otherProps.form;
const tombstoneTitle = (
<div>
<Avatar size='large' alt='Vehicle Image' src={CarImage} />
{t("jobs.fields.ro_number") + " " + jobContext.ro_number ?? "0"}
</div>
);
return ( return (
<Form onSubmit={handleSubmit} {...formItemLayout}> <Form onSubmit={handleSubmit} {...formItemLayout}>
<PageHeader <PageHeader
style={{ style={{
border: "1px solid rgb(235, 237, 240)" border: "1px solid rgb(235, 237, 240)"
}} }}
title={"RO " + jobContext.ro_number ?? "0"} title={tombstoneTitle}
subTitle={ subTitle={
jobContext.owner jobContext.owner
? (jobContext.owner?.first_name ?? "") + ? (jobContext.owner?.first_name ?? "") +
@@ -77,15 +94,29 @@ function JobTombstone({ job, ...otherProps }) {
extra={[ extra={[
<Form.Item key='1'> <Form.Item key='1'>
<Button type='primary' htmlType='submit'> <Button type='primary' htmlType='submit'>
Save {t("general.labels.save")}
</Button> </Button>
</Form.Item> </Form.Item>
]}> ]}>
<Descriptions size='small' column={3}> <Descriptions size='small' column={5}>
<Descriptions.Item label='Claim Total'> <Descriptions.Item label={t("jobs.labels.vehicle_info")}>
<Link to={`/manage/vehicles/${jobContext.vehicle?.id}`}>
{jobContext.vehicle?.v_model_yr ?? t("general.labels.na")}{" "}
{jobContext.vehicle?.v_make_desc ?? t("general.labels.na")}{" "}
{jobContext.vehicle?.v_model_desc ?? t("general.labels.na")} |{" "}
{jobContext.vehicle?.plate_no ?? t("general.labels.na")}
</Link>
</Descriptions.Item>
<Descriptions.Item label={t("jobs.fields.est_number")}>
{jobContext.est_number}
</Descriptions.Item>
<Descriptions.Item label={t("jobs.fields.claim_total")}>
$ {jobContext.claim_total?.toFixed(2)} $ {jobContext.claim_total?.toFixed(2)}
</Descriptions.Item> </Descriptions.Item>
<Descriptions.Item label='Deductible'>
<Descriptions.Item label={t("jobs.fields.deductible")}>
$ {jobContext.deductible?.toFixed(2)} $ {jobContext.deductible?.toFixed(2)}
</Descriptions.Item> </Descriptions.Item>
</Descriptions> </Descriptions>
@@ -93,17 +124,13 @@ function JobTombstone({ job, ...otherProps }) {
<Row> <Row>
<Typography.Title level={4}>Information</Typography.Title> <Typography.Title level={4}>Information</Typography.Title>
<Form.Item label='RO #'> {
{getFieldDecorator("ro_number", { // <Form.Item label='Estimate #'>
initialValue: jobContext.ro_number // {getFieldDecorator("est_number", {
})(<Input name='ro_number' readOnly onChange={handleChange} />)} // initialValue: jobContext.est_number
</Form.Item> // })(<Input name='est_number' readOnly onChange={handleChange} />)}
// </Form.Item>
<Form.Item label='Estimate #'> }
{getFieldDecorator("est_number", {
initialValue: jobContext.est_number
})(<Input name='est_number' readOnly onChange={handleChange} />)}
</Form.Item>
</Row> </Row>
<Row> <Row>

View File

@@ -4,6 +4,7 @@ import { Menu, Dropdown, Card, Icon, Avatar, Row, Col } from "antd";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import styled from "styled-components"; import styled from "styled-components";
import Moment from "react-moment"; import Moment from "react-moment";
import CarImage from "../../assets/car.svg";
//The following styled div is required because of a smooth-dnd style used by react-trello to prevent wrapping of columns. //The following styled div is required because of a smooth-dnd style used by react-trello to prevent wrapping of columns.
const WrappedSpan = styled.span` const WrappedSpan = styled.span`
@@ -80,11 +81,7 @@ export default function WhiteBoardCard({ metadata }) {
]}> ]}>
<Row> <Row>
<Col span={6}> <Col span={6}>
<Avatar <Avatar size='large' alt='Vehicle Image' src={CarImage} />
size='large'
alt='Vehicle Image'
src='https://picolio.auto123.com/auto123-media/articles/2017/9/64008/101530569fr.jpg?scaledown=450'
/>
</Col> </Col>
<Col span={18}> <Col span={18}>
<Row> <Row>
@@ -103,12 +100,14 @@ export default function WhiteBoardCard({ metadata }) {
</Row> </Row>
<Row> <Row>
<Col span={12}> <Col span={12}>
{t("general.labels.in")} {t("general.labels.in")}:
<Moment format='MM/DD/YYYY'>{metadata.actual_in}</Moment> <Moment format='MM/DD/YYYY'> {metadata.actual_in}</Moment>
</Col> </Col>
<Col span={12}> <Col span={12}>
{t("general.labels.out")} {t("general.labels.out")}:
<Moment format='MM/DD/YYYY'>{metadata.scheduled_completion}</Moment> <Moment format='MM/DD/YYYY'>
{metadata.scheduled_completion}
</Moment>
</Col> </Col>
</Row> </Row>
</Card> </Card>

View File

@@ -11,6 +11,7 @@ export default function WhiteBoardKanBan({ data, eventBus }) {
<Board <Board
tagStyle={{ fontSize: "80%" }} tagStyle={{ fontSize: "80%" }}
data={data} data={data}
style={{ backgroundColor: "none" }}
laneDraggable={false} laneDraggable={false}
eventBusHandle={setEventBus} eventBusHandle={setEventBus}
components={{ Card: WhiteBoardCard }} components={{ Card: WhiteBoardCard }}

View File

@@ -12,6 +12,7 @@ export const GET_ALL_OPEN_JOBS = gql`
scheduled_completion scheduled_completion
scheduled_delivery scheduled_delivery
vehicle { vehicle {
id
v_model_yr v_model_yr
v_make_desc v_make_desc
v_model_desc v_model_desc
@@ -38,6 +39,7 @@ export const SUBSCRIPTION_ALL_OPEN_JOBS = gql`
scheduled_completion scheduled_completion
scheduled_delivery scheduled_delivery
vehicle { vehicle {
id
v_model_yr v_model_yr
v_make_desc v_make_desc
v_model_desc v_model_desc
@@ -62,6 +64,7 @@ export const QUERY_JOBS_IN_PRODUCTION = gql`
scheduled_completion scheduled_completion
scheduled_delivery scheduled_delivery
vehicle { vehicle {
id
v_model_yr v_model_yr
v_make_desc v_make_desc
v_model_desc v_model_desc
@@ -92,6 +95,7 @@ export const SUBSCRIPTION_JOBS_IN_PRODUCTION = gql`
est_number est_number
ro_number ro_number
vehicle { vehicle {
id
v_model_yr v_model_yr
v_model_desc v_model_desc
v_make_desc v_make_desc
@@ -138,6 +142,7 @@ export const GET_JOB_BY_PK = gql`
claim_total claim_total
deductible deductible
vehicle { vehicle {
id
plate_no plate_no
v_vin v_vin
v_model_yr v_model_yr

View File

@@ -21,7 +21,6 @@ export function shouldRefreshToken(minutesBeforeShouldRefresh = 45) {
} }
export async function refreshToken() { export async function refreshToken() {
console.log("Refreshing token.")
try { try {
if (auth.user) { if (auth.user) {
const idToken = await auth().currentUser.getIdToken( const idToken = await auth().currentUser.getIdToken(
@@ -30,7 +29,7 @@ export async function refreshToken() {
const now = new Date(); const now = new Date();
window.localStorage.setItem(`lastTokenRefreshTime`, now); window.localStorage.setItem(`lastTokenRefreshTime`, now);
localStorage.setItem("token", idToken); localStorage.setItem("token", idToken);
console.log("Token refreshed.") console.log("Token refreshed.");
} }
} catch (err) { } catch (err) {
console.error(err); console.error(err);

View File

@@ -0,0 +1,5 @@
import React from "react";
export default function ErrorNotFound() {
return <div>Uh oh, we couldn't find the page you're looking for.</div>;
}

View File

@@ -8,16 +8,32 @@
}, },
"labels": { "labels": {
"in": "In", "in": "In",
"out": "Out" "out": "Out",
"na": "N/A",
"save": "Save"
} }
}, },
"jobs": { "jobs": {
"labels": { "labels": {
"no_owner": "No Owner" "no_owner": "No Owner",
"vehicle_info": "Vehicle"
}, },
"fields": { "fields": {
"ro_number": "RO #" "ro_number": "RO #",
"est_number": "Estimate Number",
"claim_total": "Claim Total",
"deductible": "Deductible"
},
"successes": {
"save": "Record Saved",
"savetitle": "Record saved succesfully."
},
"errors": {
"noaccess": "This job does not exist or you do not have access to it.",
"validationtitle": "Validation Error",
"validation": "Please ensure all fields are entered correctly.",
"saving": "Error encountered while saving record."
} }
}, },

View File

@@ -10296,6 +10296,13 @@ react-i18next@^11.2.7:
"@babel/runtime" "^7.3.1" "@babel/runtime" "^7.3.1"
html-parse-stringify2 "2.0.1" html-parse-stringify2 "2.0.1"
react-icons@^3.8.0:
version "3.8.0"
resolved "https://registry.yarnpkg.com/react-icons/-/react-icons-3.8.0.tgz#229de5904809696c9f46932bd9b6126b2522866e"
integrity sha512-rA/8GRKjPulft8BSBSMsHkE1AGPqJ7LjNsyk0BE7XjG70Iz62zOled2SJk7LDo8x9z86a3xOstDlKlMZ4pAy7A==
dependencies:
camelcase "^5.0.0"
react-is@^16.12.0, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.4, react-is@^16.8.6, react-is@^16.9.0: react-is@^16.12.0, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.4, react-is@^16.8.6, react-is@^16.9.0:
version "16.12.0" version "16.12.0"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.12.0.tgz#2cc0fe0fba742d97fd527c42a13bec4eeb06241c" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.12.0.tgz#2cc0fe0fba742d97fd527c42a13bec4eeb06241c"