Browse Source

Add timeline list

master
Garrit Franke 3 years ago
parent
commit
06df058d87
  1. 28
      client/routes/clients.js
  2. 82
      client/views/clients/Detail.jsx
  3. 29
      client/views/clients/Timeline.jsx
  4. 73
      client/views/components/ClientDetailHeader.jsx

28
client/routes/clients.js

@ -28,14 +28,34 @@ router.get("/new", async (req, res) => {
});
router.get("/:id", async (req, res) => {
const client = await axios.get(basePath + "/clients/" + req.params.id, {
headers: { Authorization: "Bearer " + req.cookies.token },
}).then(res => res.data);
const client = await axios
.get(basePath + "/clients/" + req.params.id, {
headers: { Authorization: "Bearer " + req.cookies.token },
})
.then((res) => res.data);
if (res.status === 404) {
res.render("404");
} else {
res.render("clients/Detail", { user: req.user, client });
}
});
router.get("/:id/timeline", async (req, res) => {
const client = await axios
.get(basePath + "/clients/" + req.params.id, {
headers: { Authorization: "Bearer " + req.cookies.token },
})
.then((res) => res.data);
if (res.status === 404) {
res.render("404");
} else {
res.render("clients/Detail", {user: req.user, client });
res.render("clients/Timeline", {
user: req.user,
events: client.events,
client,
});
}
});

82
client/views/clients/Detail.jsx

@ -1,12 +1,10 @@
import React from "react";
import Layout from "../layouts/Main";
import moment from "moment";
import ClientDetailHeader from "../components/ClientDetailHeader";
const basePath = process.env.API_BASE_PATH;
const frontendBasePath = process.env.FRONTEND_BASE_PATH;
export default function Detail({ client, user }) {
const timelineComponent = client.events
export default function Detail(props = { client, user }) {
const timelineComponent = props.client.events
.reverse()
.slice(0, 2)
.map((event) => {
@ -28,79 +26,17 @@ export default function Detail({ client, user }) {
</div>
);
});
console.debug(client);
return (
<Layout user={user}>
<div className="row">
<div className="col col-8">
<h4 className="display-4">{client.name}</h4>
<h4 className="lead text-muted">{client.email}</h4>
</div>
<div className="col col-4">
<div class="card border-dark">
<div class="card-body d-flex flex-column">
<div className="d-flex justify-content-between">
<span>Address</span>
<span>{client.address || "-"}</span>
</div>
<div className="d-flex justify-content-between">
<span>Tel.</span>
<span>{client.telephone || "-"}</span>
</div>
<form
method="post"
action={
basePath +
"/clients/" +
client._id +
"/events" +
"?token=" +
user.token +
"&redirect=" +
frontendBasePath +
"/clients/" +
client._id
}
class="inline"
>
<div className="d-flex justify-content-between">
<span>Status</span>
<select
className="card-text text-capitalize"
name="value"
defaultValue={client.status}
>
<option value="potential" className="card-text">
Potential
</option>
<option value="active" className="card-text">
Active
</option>
<option value="inactive" className="card-text">
Inactive
</option>
<option value="on_hold" className="card-text">
On Hold
</option>
</select>
</div>
<button
type="submit"
class="badge badge-primary align-self-end"
>
Update
</button>
<input type="hidden" name="eventType" value="status_changed" />
</form>
</div>
</div>
</div>
</div>
<Layout user={props.user}>
<ClientDetailHeader {...props} />
<div className="jumbotron jumbotron-fluid row mt-4 py-3 mx-0">
{timelineComponent}
<div className="col-sm-2 d-flex align-items-center">
<a className="btn btn-light" href={`/clients/${client._id}/timeline`}>
<a
className="btn btn-light"
href={`/clients/${props.client._id}/timeline`}
>
View Full Timeline
</a>
</div>

29
client/views/clients/Timeline.jsx

@ -0,0 +1,29 @@
import React from "react";
import Layout from "../layouts/Main";
import moment from "moment";
import ClientDetailHeader from "../components/ClientDetailHeader";
export default function Timeline(props = { client, events, user }) {
const eventViews = props.events.reverse().map((event) => {
return (
<li className="list-group-item">
<h5 className="card-title text-capitalize">
{event.eventType.replace("_", " ")}
</h5>
<h6 className="card-subtitle mb-2 text-muted">
{moment(event.createdAt).fromNow()}
</h6>
<p className="card-text text-capitalize">
{event.value?.replace("_", " ")}
</p>
</li>
);
});
return (
<Layout user={props.user}>
<ClientDetailHeader {...props} />
<ul className="list-group my-5">{eventViews}</ul>
</Layout>
);
}

73
client/views/components/ClientDetailHeader.jsx

@ -0,0 +1,73 @@
import React from "react";
import Layout from "../layouts/Main";
import moment from "moment";
const basePath = process.env.API_BASE_PATH;
const frontendBasePath = process.env.FRONTEND_BASE_PATH;
export default function ClientDetailHeader({ client, user }) {
return (
<div className="row">
<div className="col col-8">
<h4 className="display-4">{client.name}</h4>
<h4 className="lead text-muted">{client.email}</h4>
</div>
<div className="col col-4">
<div class="card border-dark">
<div class="card-body d-flex flex-column">
<div className="d-flex justify-content-between">
<span>Address</span>
<span>{client.address || "-"}</span>
</div>
<div className="d-flex justify-content-between">
<span>Tel.</span>
<span>{client.telephone || "-"}</span>
</div>
<form
method="post"
action={
basePath +
"/clients/" +
client._id +
"/events" +
"?token=" +
user.token +
"&redirect=" +
frontendBasePath +
"/clients/" +
client._id
}
class="inline"
>
<div className="d-flex justify-content-between">
<span>Status</span>
<select
className="card-text text-capitalize"
name="value"
defaultValue={client.status}
>
<option value="potential" className="card-text">
Potential
</option>
<option value="active" className="card-text">
Active
</option>
<option value="inactive" className="card-text">
Inactive
</option>
<option value="on_hold" className="card-text">
On Hold
</option>
</select>
</div>
<button type="submit" class="badge badge-primary align-self-end">
Update
</button>
<input type="hidden" name="eventType" value="status_changed" />
</form>
</div>
</div>
</div>
</div>
);
}
Loading…
Cancel
Save