Default placeholder for empty ticket and file lists. Pick a random color Indigo as main

This commit is contained in:
Ruidy Nemausat 2020-02-29 14:07:26 +01:00
parent 50d2b8b86a
commit 86fd097481
10 changed files with 129 additions and 87 deletions

View file

@ -46,7 +46,7 @@
- [ ] logging - [ ] logging
- [ ] check useRef, useReducer, dispatch - [ ] check useRef, useReducer, dispatch
- [ ] error page redirect when offline. - [ ] error page redirect when offline.
- [ ] ticket/files/activities list placeholders when empty - [x] ticket/files/activities list placeholders when empty
- [ ] think about public/private DTO's constructor, getters and setters - [ ] think about public/private DTO's constructor, getters and setters
- [x] write dtos without circular dependencies - [x] write dtos without circular dependencies
- [ ] use dtoRequest for PutProjects - [ ] use dtoRequest for PutProjects

View file

@ -1,5 +1,6 @@
import React, { FC } from "react"; import React, { FC } from "react";
import { Activity } from "../types/Activity"; import { Activity } from "../types/Activity";
import { act } from "react-dom/test-utils";
type IProps = { type IProps = {
activities: Activity[]; activities: Activity[];
@ -12,38 +13,58 @@ export const ActivityCollection: FC<IProps> = ({ activities, filterText }) => {
) : ( ) : (
<> <>
<ul className="collection"> <ul className="collection">
{activities {activities.length === 0 ? (
.filter( <ActivityEntry />
a => ) : (
a.description.toLowerCase().includes(filterText.toLowerCase()) || activities
a.user.firstName .filter(
.toLowerCase() a =>
.includes(filterText.toLowerCase()) || a.description
a.ticket.title.toLowerCase().includes(filterText.toLowerCase()) .toLowerCase()
) .includes(filterText.toLowerCase()) ||
.map((activity: Activity) => ( a.user.firstName
<li key={activity.id} className="collection-item avatar"> .toLowerCase()
<ActivityEntry activity={activity} /> .includes(filterText.toLowerCase()) ||
</li> a.ticket.title.toLowerCase().includes(filterText.toLowerCase())
))} )
.map((activity: Activity) => (
<ActivityEntry activity={activity} key={activity.id} />
))
)}
</ul> </ul>
</> </>
); );
}; };
type IFProps = { type IFProps = {
activity: Activity; activity?: Activity;
}; };
export const ActivityEntry: FC<IFProps> = ({ activity }) => { export const ActivityEntry: FC<IFProps> = ({ activity }) => {
return ( return (
<> <>
<img src={activity.user.picture} alt="" className="circle" /> <li className="collection-item avatar">
{/* <i className="material-icons circle">folder</i> */} {/* <img
<span className="title"> src={
{activity.user.firstName} {activity.description} {activity.ticket.title} activity
</span> ? activity.user.picture
<p>{activity.date.toDateString()}</p> : "https://previews.123rf.com/images/vikpit/vikpit1604/vikpit160400034/54976526-welcome-sign-symbol-word-welcome-hand-lettering-calligraphic-font-letters-and-shade-isolated-on-whit.jpg"
}
alt=""
height="32vh"
width="32vh"
className="circle"
/> */}
<i className="material-icons circle indigo lighten-1">folder</i>
<span className="title">
{activity ? activity.user.firstName : "Ruidy"}
{activity ? activity.description : " welcomes you "}
{activity ? activity.ticket.title : "here"}
</span>
<p>
{activity ? activity.date.toDateString() : new Date().toDateString()}
</p>
</li>
</> </>
); );
}; };

View file

@ -7,35 +7,38 @@ type IProps = {
}; };
export const FileCollection: FC<IProps> = ({ files, filterText }) => { export const FileCollection: FC<IProps> = ({ files, filterText }) => {
console.log();
return ( return (
<> <>
<ul className="collection"> <ul className="collection">
{files {files.length === 0 ? (
.filter( <FileEntry />
f => ) : (
f.name.toLowerCase().includes(filterText.toLowerCase()) || files
f.format.toLowerCase().includes(filterText.toLowerCase()) .filter(
) f =>
.map((file: AppFile) => ( f.name.toLowerCase().includes(filterText.toLowerCase()) ||
<FileEntry file={file} key={file.id} /> f.format.toLowerCase().includes(filterText.toLowerCase())
))} )
.map((file: AppFile) => <FileEntry file={file} key={file.id} />)
)}
</ul> </ul>
</> </>
); );
}; };
type IFProps = { type IFProps = {
file: AppFile; file?: AppFile;
}; };
export const FileEntry: FC<IFProps> = ({ file }) => { export const FileEntry: FC<IFProps> = ({ file }) => {
return ( return (
<li className="collection-item avatar"> <li className="collection-item avatar">
{/* <img src={require("../images/user_1.jpg")} alt="" className="circle" /> */} {/* <img src={require("../images/user_1.jpg")} alt="" className="circle" /> */}
<i className="material-icons circle">folder</i> <i className="material-icons circle indigo lighten-1">folder</i>
<span className="title">{file.name}</span> <span className="title">{file ? file.name : "Add your first file"}</span>
<p> <p>
{file.size}kb {file.format} {file ? file.size : 0}kb {file ? file.format : "pdf"}
</p> </p>
<a href="#!" className="secondary-content"> <a href="#!" className="secondary-content">
<i className="material-icons">more_vert</i> <i className="material-icons">more_vert</i>

View file

@ -3,9 +3,9 @@ import { Link } from "react-router-dom";
import { getRemainingdays } from "../utils/methods"; import { getRemainingdays } from "../utils/methods";
interface IProps { interface IProps {
title: string; title?: string;
remainingDays: string; remainingDays?: string;
validateTicket: (event: MouseEvent) => void; validateTicket?: (event: MouseEvent) => void;
// archiveTicket: (event: MouseEvent) => void; // archiveTicket: (event: MouseEvent) => void;
} }
@ -16,33 +16,45 @@ export const HorizontalCard: FC<IProps> = ({
validateTicket validateTicket
}) => { }) => {
return ( return (
<div className="card horizontal"> <li>
<div className="card-stacked"> <div className="card horizontal">
<div className="card-content"> <div className="card-stacked">
<div className="row"> <div className="card-content">
<div className="card-title"> <div className="row">
<h6> <div className="card-title">
<h6>
<Link to="#">
<b>{title ?? "Nothing to do"}</b>
</Link>
</h6>
</div>
<span>
Due{" "}
{remainingDays ? (
getRemainingdays(remainingDays)
) : (
<span>
<del>Too much</del> 0
</span>
)}{" "}
days
</span>
<div className="right">
<Link to="#"> <Link to="#">
<b>{title}</b> <i className="material-icons" onClick={validateTicket}>
check
</i>
</Link> </Link>
</h6> {/* <Link to="#">
</div>
<span>Due {getRemainingdays(remainingDays)} days</span>
<div className="right">
<Link to="#">
<i className="material-icons" onClick={validateTicket}>
check
</i>
</Link>
{/* <Link to="#">
<i className="material-icons" onClick={archiveTicket}> <i className="material-icons" onClick={archiveTicket}>
archive archive
</i> </i>
</Link> */} </Link> */}
</div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </li>
); );
}; };

View file

@ -7,7 +7,7 @@ export const InputFile: FC<IProps> = () => {
<> <>
<form action="/upload"> <form action="/upload">
<div className="file-field input-field"> <div className="file-field input-field">
<div className="btn"> <div className="btn indigo lighten-1">
<i className="material-icons ">cloud_upload</i> <i className="material-icons ">cloud_upload</i>
<input <input
type="file" type="file"

View file

@ -16,11 +16,12 @@ export const ProgressBar: FC<ProgressBarProps> = ({
remainingDays remainingDays
}) => { }) => {
const styleString: CSSProperties = { width: `${value}%` }; const styleString: CSSProperties = { width: `${value}%` };
const barColor: string = value < 75 ? "red" : "";
return ( return (
<> <>
<div className="row"> <div className="row">
<div className="progress"> <div className="progress">
<div className="determinate" style={styleString}></div> <div className={`determinate ${barColor}`} style={styleString}></div>
</div> </div>
<div> <div>
<i className="left material-icons">playlist_add_check</i> <i className="left material-icons">playlist_add_check</i>

View file

@ -14,7 +14,7 @@ export const TabRouterHeader: FC<IProps> = ({
const nTabs = tabNames.length; const nTabs = tabNames.length;
return ( return (
<> <>
<ul className="tabs z-depth-1"> <ul className="tabs">
{tabNames.map((name, i) => ( {tabNames.map((name, i) => (
<TabUnit <TabUnit
key={i} key={i}
@ -27,7 +27,7 @@ export const TabRouterHeader: FC<IProps> = ({
/> />
))} ))}
<li <li
className="indicator" className="indicator indigo lighten-2"
style={{ style={{
left: `${(isActive / nTabs) * 100}%`, left: `${(isActive / nTabs) * 100}%`,
right: `${(1 - (isActive + 1) / nTabs) * 100}%` right: `${(1 - (isActive + 1) / nTabs) * 100}%`
@ -68,7 +68,11 @@ const TabUnit: FC<TabUnitProps> = ({
<Link <Link
to={`${url}/${text}`} to={`${url}/${text}`}
id={value} id={value}
className={isActive === parseInt(value) ? "active pink lighten-5" : ""} className={
isActive === parseInt(value)
? "active indigo lighten-5 indigo-text"
: "indigo-text"
}
onClick={() => setIsActive(parseInt(value))} onClick={() => setIsActive(parseInt(value))}
> >
{text} {text}

View file

@ -30,7 +30,11 @@ export const TicketList: FC<TicketListProps> = ({ tickets }) => {
}; };
const [showNew, setShowNew] = useState(false); const [showNew, setShowNew] = useState(false);
let filteredTickets = tickets.filter(
t =>
t.status !== "Done" &&
t.title.toLowerCase().includes(filterText.toLowerCase())
);
return ( return (
<> <>
<div className="row valign-wrapper"> <div className="row valign-wrapper">
@ -42,7 +46,7 @@ export const TicketList: FC<TicketListProps> = ({ tickets }) => {
/> />
<h3>Tickets</h3> <h3>Tickets</h3>
<FloatingButton <FloatingButton
color=" blue-grey lighten-4" color="indigo lighten-1"
size="small" size="small"
onClick={onClick} onClick={onClick}
/> />
@ -54,28 +58,25 @@ export const TicketList: FC<TicketListProps> = ({ tickets }) => {
</div> </div>
<div className="col s12 grey"> <div className="col s12 grey">
<ul> <ul>
{tickets {filteredTickets.length === 0 ? (
.filter( <HorizontalCard />
t => ) : (
t.status !== "Done" && filteredTickets.map((t: Ticket) => (
t.title.toLowerCase().includes(filterText.toLowerCase()) <HorizontalCard
) key={t.id}
.map((t: Ticket) => ( title={t.title}
<li key={t.id}> remainingDays={t.plannedEnding}
<HorizontalCard validateTicket={async (e: MouseEvent) => {
title={t.title} e.preventDefault();
remainingDays={t.plannedEnding} await put<HttpResponse<Ticket>>(
validateTicket={async (e: MouseEvent) => { `${Constants.ticketsURI}/${t.id}/closed`,
e.preventDefault(); {}
await put<HttpResponse<Ticket>>( );
`${Constants.ticketsURI}/${t.id}/closed`, }}
{} // archiveTicket={archiveTicket}
); />
}} ))
// archiveTicket={archiveTicket} )}
/>
</li>
))}
</ul> </ul>
</div> </div>
</> </>

View file

@ -37,7 +37,7 @@ export const ProjectPage: FC<IProps> = ({ viewModel }) => {
<AvatarList users={users} /> <AvatarList users={users} />
<FloatingButton <FloatingButton
icon="add" icon="add"
color="grey" color="indigo lighten-1"
size="small" size="small"
onClick={() => setShowModal(true)} onClick={() => setShowModal(true)}
/> />

View file

@ -20,7 +20,7 @@ export const history = creacteHistory.createBrowserHistory();
export const AppRouter = () => { export const AppRouter = () => {
return ( return (
<Router history={history}> <Router history={history}>
<div className="grey lighten-4"> <div className="grey lighten-3">
<Switch> <Switch>
<Route exact path="/"> <Route exact path="/">
<TestPage /> <TestPage />