Fixed selected nav item. Added lazy loading for WS client to resolve token issue. Added some filtering to jobs list.

This commit is contained in:
Patrick Fic
2019-12-12 12:23:31 -08:00
parent f6c62da40a
commit bca375251e
9 changed files with 266 additions and 42 deletions

View File

@@ -30,6 +30,7 @@ class AppContainer extends Component {
const wsLink = new WebSocketLink({
uri: process.env.REACT_APP_GRAPHQL_ENDPOINT_WS,
options: {
lazy: true,
reconnect: true,
connectionParams: () => {
const token = localStorage.getItem("token");
@@ -49,7 +50,11 @@ class AppContainer extends Component {
({ query }) => {
const definition = getMainDefinition(query);
console.log(
"##Intercepted GQL Transaction##" + definition.operation,
"##Intercepted GQL Transaction : " +
definition.operation +
"|" +
definition.name.value +
"##",
query
);
return (

View File

@@ -13,20 +13,17 @@ import SignInPage from "../pages/sign-in/sign-in.page";
import Unauthorized from "../pages/unauthorized/unauthorized.component";
import { auth } from "../firebase/firebase.utils";
import { UPSERT_USER } from "../graphql/user.queries";
import { GET_CURRENT_USER } from "../graphql/local.queries";
import LoadingSpinner from "../components/loading-spinner/loading-spinner.component";
import AlertComponent from "../components/alert/alert.component";
import SignOut from "../components/sign-out/sign-out.component";
import { UPSERT_USER } from "../graphql/user.queries";
export default () => {
const apolloClient = useApolloClient();
useEffect(() => {
//Run the auth code only on the first render.
const unsubscribeFromAuth = auth.onAuthStateChanged(async user => {
const unsubscribeFromAuth = auth.onIdTokenChanged(async user => {
if (user) {
let token;
token = await user.getIdToken();
@@ -85,7 +82,6 @@ export default () => {
return <AlertComponent message={HookCurrentUser.error.message} />;
return (
<div>
<SignOut />
<Switch>
<Route exact path="/" component={LandingPage} />
<Route exact path="/unauthorized" component={Unauthorized} />

View File

@@ -0,0 +1,80 @@
import React from "react";
import { Icon, Button, Input, AutoComplete } from "antd";
const { Option } = AutoComplete;
function onSelect(value) {
console.log("onSelect", value);
}
function getRandomInt(max, min = 0) {
return Math.floor(Math.random() * (max - min + 1)) + min; // eslint-disable-line no-mixed-operators
}
function searchResult(query) {
return new Array(getRandomInt(5))
.join(".")
.split(".")
.map((item, idx) => ({
query,
category: `${query}${idx}`,
count: getRandomInt(200, 100)
}));
}
function renderOption(item) {
return (
<Option key={item.category} text={item.category}>
<div className="global-search-item">
<span className="global-search-item-desc">
Found {item.query} on
<a
href={`https://s.taobao.com/search?q=${item.query}`}
target="_blank"
rel="noopener noreferrer"
>
{item.category}
</a>
</span>
<span className="global-search-item-count">{item.count} results</span>
</div>
</Option>
);
}
export default class GlobalSearch extends React.Component {
state = {
dataSource: []
};
handleSearch = value => {
this.setState({
dataSource: value ? searchResult(value) : []
});
};
render() {
const { dataSource } = this.state;
return (
<div style={{ width: 300 }}>
<AutoComplete
size="large"
style={{ width: "100%" }}
dataSource={dataSource.map(renderOption)}
onSelect={onSelect}
onSearch={this.handleSearch}
placeholder="input here"
optionLabelProp="text"
>
<Input
suffix={
<Button style={{ marginRight: -12 }} size="large" type="primary">
<Icon type="search" />
</Button>
}
/>
</AutoComplete>
</div>
);
}
}

View File

@@ -8,38 +8,56 @@ import {
GET_LANDING_NAV_ITEMS,
GET_NAV_ITEMS
} from "../../graphql/metadata.queries";
import { GET_CURRENT_SELECTED_NAV_ITEM } from "../../graphql/local.queries";
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
import AlertComponent from "../alert/alert.component";
import ManageSignInButton from "../manage-sign-in-button/manage-sign-in-button.component";
import { useApolloClient } from "@apollo/react-hooks";
import GlobalSearch from "../global-search/global-search.component";
export default ({ landingHeader }) => {
let HookNavItems;
export default ({ landingHeader, signedIn }) => {
const apolloClient = useApolloClient();
const hookSelectedNavItem = useQuery(GET_CURRENT_SELECTED_NAV_ITEM);
let hookNavItems;
if (landingHeader) {
HookNavItems = useQuery(GET_LANDING_NAV_ITEMS);
hookNavItems = useQuery(GET_LANDING_NAV_ITEMS, {
fetchPolicy: "network-only"
});
} else {
HookNavItems = useQuery(GET_NAV_ITEMS);
hookNavItems = useQuery(GET_NAV_ITEMS, {
fetchPolicy: "network-only"
});
}
const handleClick = e => {
console.log("click ", e);
// this.setState({
// current: e.key
// });
apolloClient.writeData({ data: { selectedNavItem: e.key } });
};
if (HookNavItems.loading) return <LoadingSpinner />;
if (HookNavItems.error)
return <AlertComponent message={HookNavItems.error.message} />;
if (hookNavItems.loading || hookSelectedNavItem.loading)
return <LoadingSpinner />;
if (hookNavItems.error)
return <AlertComponent message={hookNavItems.error.message} />;
if (hookSelectedNavItem.error)
return console.log(
"Unable to load Selected Navigation Item.",
hookSelectedNavItem.error
);
const { selectedNavItem } = hookSelectedNavItem.data;
const navItems = JSON.parse(hookNavItems.data.masterdata_by_pk.value);
const navItems = JSON.parse(HookNavItems.data.masterdata_by_pk.value);
return (
<Menu
theme="dark"
className="header"
onClick={handleClick}
selectedKeys="Home"
selectedKeys={selectedNavItem}
mode="horizontal"
>
<Menu.Item>
<GlobalSearch />
</Menu.Item>
{navItems.map(navItem => (
<Menu.Item key={navItem.title}>
<Link to={navItem.path}>
@@ -48,11 +66,16 @@ export default ({ landingHeader }) => {
</Link>
</Menu.Item>
))}
{!landingHeader ? (
<Menu.Item>
<SignOut />
</Menu.Item>
) : null}
) : (
<Menu.Item>
<ManageSignInButton />
</Menu.Item>
)}
</Menu>
);
};

View File

@@ -0,0 +1,33 @@
import React from "react";
import { useQuery } from "react-apollo";
import { Link } from "react-router-dom";
import { GET_CURRENT_USER } from "../../graphql/local.queries";
import { Icon } from "antd";
export default function ManageSignInButton() {
const {
loading,
error,
data: { currentUser }
} = useQuery(GET_CURRENT_USER);
if (loading) return "MSI Loading";
if (error) return error.message;
console.log("currentUser", currentUser);
return currentUser ? (
<div>
{" "}
<Link to="/manage">
<Icon type="build" />
Manage
</Link>
</div>
) : (
<div>
<Link to="/signin">
<Icon type="login" />
Sign In
</Link>
</div>
);
}

View File

@@ -9,7 +9,7 @@ export const SET_CURRENT_USER = gql`
`;
export const GET_CURRENT_USER = gql`
{
query GET_CURRENT_USER {
currentUser @client {
email
displayName
@@ -20,6 +20,12 @@ export const GET_CURRENT_USER = gql`
}
`;
export const GET_CURRENT_SELECTED_NAV_ITEM = gql`
query GET_CURRENT_SELECTED_NAV_ITEM {
selectedNavItem @client
}
`;
export const GET_WHITE_BOARD_LEFT_SIDER_VISIBLE = gql`
{
whiteBoardLeftSiderVisible @client

View File

@@ -1,18 +1,16 @@
import React from "react";
import { useQuery, useSubscription } from "@apollo/react-hooks";
import React, { useState } from "react";
import { useSubscription } from "@apollo/react-hooks";
import AlertComponent from "../../components/alert/alert.component";
//import { GET_ALL_OPEN_JOBS } from "../../graphql/jobs.queries";
import { Table, Divider, Icon } from "antd";
import { alphaSort } from "../../utils/sorters";
import {
GET_ALL_OPEN_JOBS,
SUBSCRIPTION_ALL_OPEN_JOBS
} from "../../graphql/jobs.queries";
import { SUBSCRIPTION_ALL_OPEN_JOBS } from "../../graphql/jobs.queries";
//import { columns } from "./jobs.page.metadata";
export default function JobsPage() {
// const { loading, error, data } = useQuery(GET_ALL_OPEN_JOBS, {
// fetchPolicy: "network-only"
// });
const [sortedInfo, setSortedInfo] = useState({});
const { loading, error, data } = useSubscription(SUBSCRIPTION_ALL_OPEN_JOBS, {
fetchPolicy: "network-only"
});
@@ -21,7 +19,10 @@ export default function JobsPage() {
{
title: "RO #",
dataIndex: "ro_number",
key: "ro_number"
key: "ro_number",
sorter: (a, b) => alphaSort(a, b),
sortOrder: sortedInfo.columnKey === "ro_number" && sortedInfo.order,
ellipsis: true
},
{
title: "Est. #",
@@ -31,7 +32,10 @@ export default function JobsPage() {
{
title: "Status",
dataIndex: "status",
key: "status"
key: "status",
sorter: (a, b) => alphaSort(a, b),
sortOrder: sortedInfo.columnKey === "status" && sortedInfo.order,
ellipsis: true
},
{
title: "Customer",
@@ -67,22 +71,25 @@ export default function JobsPage() {
key: "action",
render: (text, record) => (
<span>
<a>Action {record.ro_number}</a>
Action {record.ro_number}
<Divider type="vertical" />
<a>Delete</a>
<Divider type="vertical" />
<a className="ant-dropdown-link">
More actions <Icon type="down" />
</a>
More actions <Icon type="down" />
</span>
)
}
];
if (error) {
console.log("error", error);
return <AlertComponent message={error} />;
}
const handleChange = (pagination, filters, sorter) => {
console.log("Various parameters", pagination, filters, sorter);
// this.setState({
// filteredInfo: filters,
// sortedInfo: sorter,
// });
setSortedInfo(sorter);
};
if (error) return <AlertComponent message={error.message} />;
return (
<div>
@@ -92,6 +99,7 @@ export default function JobsPage() {
columns={columns.map(item => ({ ...item }))}
rowKey="id"
dataSource={data ? data.jobs : null}
onChange={handleChange}
/>
</div>
);

View File

@@ -0,0 +1,64 @@
import React from "react";
import { Divider, Icon } from "antd";
export const columns = [
{
title: "RO #",
dataIndex: "ro_number",
key: "ro_number",
sorter: (a, b) => a.ro_number > b.ro_number,
sortOrder: sortedInfo.columnKey === "ro_number" && sortedInfo.order,
ellipsis: true
},
{
title: "Est. #",
dataIndex: "est_number",
key: "est_number"
},
{
title: "Status",
dataIndex: "status",
key: "status"
},
{
title: "Customer",
dataIndex: "customer",
key: "customer",
render: (text, record) => {
return record.owner ? (
<div>
{record.owner.first_name} {record.owner.last_name}
</div>
) : (
"No Customer"
);
}
},
{
title: "Vehicle",
dataIndex: "vehicle",
key: "vehicle",
render: (text, record) => {
return record.vehicle ? (
<div>
{record.vehicle.v_model_yr} {record.vehicle.v_make_desc}{" "}
{record.vehicle.v_model_desc}
</div>
) : (
"No Vehicle"
);
}
},
{
title: "Action",
key: "action",
render: (text, record) => (
<span>
Action {record.ro_number}
<Divider type="vertical" />
<Divider type="vertical" />
More actions <Icon type="down" />
</span>
)
}
];

View File

@@ -0,0 +1,9 @@
export function alphaSort(a, b) {
if (a > b) {
return false;
}
if (b > a) {
return true;
}
return true;
}