mirror of
https://github.com/rjNemo/ticket_manager
synced 2026-06-06 00:36:39 +00:00
Default placeholder for empty ticket and file lists. Pick a random color Indigo as main
This commit is contained in:
parent
50d2b8b86a
commit
86fd097481
10 changed files with 129 additions and 87 deletions
|
|
@ -46,7 +46,7 @@
|
|||
- [ ] logging
|
||||
- [ ] check useRef, useReducer, dispatch
|
||||
- [ ] 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
|
||||
- [x] write dtos without circular dependencies
|
||||
- [ ] use dtoRequest for PutProjects
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import React, { FC } from "react";
|
||||
import { Activity } from "../types/Activity";
|
||||
import { act } from "react-dom/test-utils";
|
||||
|
||||
type IProps = {
|
||||
activities: Activity[];
|
||||
|
|
@ -12,38 +13,58 @@ export const ActivityCollection: FC<IProps> = ({ activities, filterText }) => {
|
|||
) : (
|
||||
<>
|
||||
<ul className="collection">
|
||||
{activities
|
||||
.filter(
|
||||
a =>
|
||||
a.description.toLowerCase().includes(filterText.toLowerCase()) ||
|
||||
a.user.firstName
|
||||
.toLowerCase()
|
||||
.includes(filterText.toLowerCase()) ||
|
||||
a.ticket.title.toLowerCase().includes(filterText.toLowerCase())
|
||||
)
|
||||
.map((activity: Activity) => (
|
||||
<li key={activity.id} className="collection-item avatar">
|
||||
<ActivityEntry activity={activity} />
|
||||
</li>
|
||||
))}
|
||||
{activities.length === 0 ? (
|
||||
<ActivityEntry />
|
||||
) : (
|
||||
activities
|
||||
.filter(
|
||||
a =>
|
||||
a.description
|
||||
.toLowerCase()
|
||||
.includes(filterText.toLowerCase()) ||
|
||||
a.user.firstName
|
||||
.toLowerCase()
|
||||
.includes(filterText.toLowerCase()) ||
|
||||
a.ticket.title.toLowerCase().includes(filterText.toLowerCase())
|
||||
)
|
||||
.map((activity: Activity) => (
|
||||
<ActivityEntry activity={activity} key={activity.id} />
|
||||
))
|
||||
)}
|
||||
</ul>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
type IFProps = {
|
||||
activity: Activity;
|
||||
activity?: Activity;
|
||||
};
|
||||
|
||||
export const ActivityEntry: FC<IFProps> = ({ activity }) => {
|
||||
return (
|
||||
<>
|
||||
<img src={activity.user.picture} alt="" className="circle" />
|
||||
{/* <i className="material-icons circle">folder</i> */}
|
||||
<span className="title">
|
||||
{activity.user.firstName} {activity.description} {activity.ticket.title}
|
||||
</span>
|
||||
<p>{activity.date.toDateString()}</p>
|
||||
<li className="collection-item avatar">
|
||||
{/* <img
|
||||
src={
|
||||
activity
|
||||
? activity.user.picture
|
||||
: "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>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -7,35 +7,38 @@ type IProps = {
|
|||
};
|
||||
|
||||
export const FileCollection: FC<IProps> = ({ files, filterText }) => {
|
||||
console.log();
|
||||
return (
|
||||
<>
|
||||
<ul className="collection">
|
||||
{files
|
||||
.filter(
|
||||
f =>
|
||||
f.name.toLowerCase().includes(filterText.toLowerCase()) ||
|
||||
f.format.toLowerCase().includes(filterText.toLowerCase())
|
||||
)
|
||||
.map((file: AppFile) => (
|
||||
<FileEntry file={file} key={file.id} />
|
||||
))}
|
||||
{files.length === 0 ? (
|
||||
<FileEntry />
|
||||
) : (
|
||||
files
|
||||
.filter(
|
||||
f =>
|
||||
f.name.toLowerCase().includes(filterText.toLowerCase()) ||
|
||||
f.format.toLowerCase().includes(filterText.toLowerCase())
|
||||
)
|
||||
.map((file: AppFile) => <FileEntry file={file} key={file.id} />)
|
||||
)}
|
||||
</ul>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
type IFProps = {
|
||||
file: AppFile;
|
||||
file?: AppFile;
|
||||
};
|
||||
|
||||
export const FileEntry: FC<IFProps> = ({ file }) => {
|
||||
return (
|
||||
<li className="collection-item avatar">
|
||||
{/* <img src={require("../images/user_1.jpg")} alt="" className="circle" /> */}
|
||||
<i className="material-icons circle">folder</i>
|
||||
<span className="title">{file.name}</span>
|
||||
<i className="material-icons circle indigo lighten-1">folder</i>
|
||||
<span className="title">{file ? file.name : "Add your first file"}</span>
|
||||
<p>
|
||||
{file.size}kb {file.format}
|
||||
{file ? file.size : 0}kb {file ? file.format : "pdf"}
|
||||
</p>
|
||||
<a href="#!" className="secondary-content">
|
||||
<i className="material-icons">more_vert</i>
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@ import { Link } from "react-router-dom";
|
|||
import { getRemainingdays } from "../utils/methods";
|
||||
|
||||
interface IProps {
|
||||
title: string;
|
||||
remainingDays: string;
|
||||
validateTicket: (event: MouseEvent) => void;
|
||||
title?: string;
|
||||
remainingDays?: string;
|
||||
validateTicket?: (event: MouseEvent) => void;
|
||||
// archiveTicket: (event: MouseEvent) => void;
|
||||
}
|
||||
|
||||
|
|
@ -16,33 +16,45 @@ export const HorizontalCard: FC<IProps> = ({
|
|||
validateTicket
|
||||
}) => {
|
||||
return (
|
||||
<div className="card horizontal">
|
||||
<div className="card-stacked">
|
||||
<div className="card-content">
|
||||
<div className="row">
|
||||
<div className="card-title">
|
||||
<h6>
|
||||
<li>
|
||||
<div className="card horizontal">
|
||||
<div className="card-stacked">
|
||||
<div className="card-content">
|
||||
<div className="row">
|
||||
<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="#">
|
||||
<b>{title}</b>
|
||||
<i className="material-icons" onClick={validateTicket}>
|
||||
check
|
||||
</i>
|
||||
</Link>
|
||||
</h6>
|
||||
</div>
|
||||
<span>Due {getRemainingdays(remainingDays)} days</span>
|
||||
<div className="right">
|
||||
<Link to="#">
|
||||
<i className="material-icons" onClick={validateTicket}>
|
||||
check
|
||||
</i>
|
||||
</Link>
|
||||
{/* <Link to="#">
|
||||
{/* <Link to="#">
|
||||
<i className="material-icons" onClick={archiveTicket}>
|
||||
archive
|
||||
</i>
|
||||
</Link> */}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ export const InputFile: FC<IProps> = () => {
|
|||
<>
|
||||
<form action="/upload">
|
||||
<div className="file-field input-field">
|
||||
<div className="btn">
|
||||
<div className="btn indigo lighten-1">
|
||||
<i className="material-icons ">cloud_upload</i>
|
||||
<input
|
||||
type="file"
|
||||
|
|
|
|||
|
|
@ -16,11 +16,12 @@ export const ProgressBar: FC<ProgressBarProps> = ({
|
|||
remainingDays
|
||||
}) => {
|
||||
const styleString: CSSProperties = { width: `${value}%` };
|
||||
const barColor: string = value < 75 ? "red" : "";
|
||||
return (
|
||||
<>
|
||||
<div className="row">
|
||||
<div className="progress">
|
||||
<div className="determinate" style={styleString}></div>
|
||||
<div className={`determinate ${barColor}`} style={styleString}></div>
|
||||
</div>
|
||||
<div>
|
||||
<i className="left material-icons">playlist_add_check</i>
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ export const TabRouterHeader: FC<IProps> = ({
|
|||
const nTabs = tabNames.length;
|
||||
return (
|
||||
<>
|
||||
<ul className="tabs z-depth-1">
|
||||
<ul className="tabs">
|
||||
{tabNames.map((name, i) => (
|
||||
<TabUnit
|
||||
key={i}
|
||||
|
|
@ -27,7 +27,7 @@ export const TabRouterHeader: FC<IProps> = ({
|
|||
/>
|
||||
))}
|
||||
<li
|
||||
className="indicator"
|
||||
className="indicator indigo lighten-2"
|
||||
style={{
|
||||
left: `${(isActive / nTabs) * 100}%`,
|
||||
right: `${(1 - (isActive + 1) / nTabs) * 100}%`
|
||||
|
|
@ -68,7 +68,11 @@ const TabUnit: FC<TabUnitProps> = ({
|
|||
<Link
|
||||
to={`${url}/${text}`}
|
||||
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))}
|
||||
>
|
||||
{text}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,11 @@ export const TicketList: FC<TicketListProps> = ({ tickets }) => {
|
|||
};
|
||||
|
||||
const [showNew, setShowNew] = useState(false);
|
||||
|
||||
let filteredTickets = tickets.filter(
|
||||
t =>
|
||||
t.status !== "Done" &&
|
||||
t.title.toLowerCase().includes(filterText.toLowerCase())
|
||||
);
|
||||
return (
|
||||
<>
|
||||
<div className="row valign-wrapper">
|
||||
|
|
@ -42,7 +46,7 @@ export const TicketList: FC<TicketListProps> = ({ tickets }) => {
|
|||
/>
|
||||
<h3>Tickets</h3>
|
||||
<FloatingButton
|
||||
color=" blue-grey lighten-4"
|
||||
color="indigo lighten-1"
|
||||
size="small"
|
||||
onClick={onClick}
|
||||
/>
|
||||
|
|
@ -54,28 +58,25 @@ export const TicketList: FC<TicketListProps> = ({ tickets }) => {
|
|||
</div>
|
||||
<div className="col s12 grey">
|
||||
<ul>
|
||||
{tickets
|
||||
.filter(
|
||||
t =>
|
||||
t.status !== "Done" &&
|
||||
t.title.toLowerCase().includes(filterText.toLowerCase())
|
||||
)
|
||||
.map((t: Ticket) => (
|
||||
<li key={t.id}>
|
||||
<HorizontalCard
|
||||
title={t.title}
|
||||
remainingDays={t.plannedEnding}
|
||||
validateTicket={async (e: MouseEvent) => {
|
||||
e.preventDefault();
|
||||
await put<HttpResponse<Ticket>>(
|
||||
`${Constants.ticketsURI}/${t.id}/closed`,
|
||||
{}
|
||||
);
|
||||
}}
|
||||
// archiveTicket={archiveTicket}
|
||||
/>
|
||||
</li>
|
||||
))}
|
||||
{filteredTickets.length === 0 ? (
|
||||
<HorizontalCard />
|
||||
) : (
|
||||
filteredTickets.map((t: Ticket) => (
|
||||
<HorizontalCard
|
||||
key={t.id}
|
||||
title={t.title}
|
||||
remainingDays={t.plannedEnding}
|
||||
validateTicket={async (e: MouseEvent) => {
|
||||
e.preventDefault();
|
||||
await put<HttpResponse<Ticket>>(
|
||||
`${Constants.ticketsURI}/${t.id}/closed`,
|
||||
{}
|
||||
);
|
||||
}}
|
||||
// archiveTicket={archiveTicket}
|
||||
/>
|
||||
))
|
||||
)}
|
||||
</ul>
|
||||
</div>
|
||||
</>
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ export const ProjectPage: FC<IProps> = ({ viewModel }) => {
|
|||
<AvatarList users={users} />
|
||||
<FloatingButton
|
||||
icon="add"
|
||||
color="grey"
|
||||
color="indigo lighten-1"
|
||||
size="small"
|
||||
onClick={() => setShowModal(true)}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ export const history = creacteHistory.createBrowserHistory();
|
|||
export const AppRouter = () => {
|
||||
return (
|
||||
<Router history={history}>
|
||||
<div className="grey lighten-4">
|
||||
<div className="grey lighten-3">
|
||||
<Switch>
|
||||
<Route exact path="/">
|
||||
<TestPage />
|
||||
|
|
|
|||
Loading…
Reference in a new issue