mirror of
https://github.com/rjNemo/ticket_manager
synced 2026-06-06 00:36:39 +00:00
Static Project page done. Activity & Files tabs added. Preloader added. Changed History to Activity
This commit is contained in:
parent
b861a65892
commit
0990e59d64
18 changed files with 288 additions and 16 deletions
|
|
@ -44,3 +44,4 @@
|
|||
- update assignments automatically from context
|
||||
- use PATCH instead of PUT
|
||||
- logging
|
||||
- check useRef, useReducer, dispatch
|
||||
|
|
|
|||
35
client/src/components/ActivityCollection.tsx
Normal file
35
client/src/components/ActivityCollection.tsx
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
import React, { FC } from "react";
|
||||
import { Activity } from "../types/Activity";
|
||||
|
||||
type IProps = {
|
||||
activities: Activity[];
|
||||
};
|
||||
|
||||
export const ActivityCollection: FC<IProps> = ({ activities }) => {
|
||||
return (
|
||||
<>
|
||||
<ul className="collection">
|
||||
{activities.map((f: Activity) => (
|
||||
<ActivityEntry activity={f} />
|
||||
))}
|
||||
</ul>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
type IFProps = {
|
||||
activity: Activity;
|
||||
};
|
||||
|
||||
export const ActivityEntry: FC<IFProps> = ({ activity }) => {
|
||||
return (
|
||||
<li key={activity.id} className="collection-item avatar">
|
||||
<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>
|
||||
);
|
||||
};
|
||||
20
client/src/components/ActivityList.tsx
Normal file
20
client/src/components/ActivityList.tsx
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
import React, { FC } from "react";
|
||||
import { FloatingButton } from "./FloatingButton";
|
||||
import { ActivityCollection } from "./ActivityCollection";
|
||||
import { Activity } from "../types/Activity";
|
||||
|
||||
type IProps = {
|
||||
activities: Activity[];
|
||||
};
|
||||
|
||||
export const ActivityList: FC<IProps> = ({ activities }) => {
|
||||
return (
|
||||
<>
|
||||
<div className="row valign-wrapper">
|
||||
<h3>Activity</h3>
|
||||
<FloatingButton color=" blue-grey lighten-4" size="" />
|
||||
</div>
|
||||
<ActivityCollection activities={activities} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
22
client/src/components/AppFileList.tsx
Normal file
22
client/src/components/AppFileList.tsx
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
import React, { FC } from "react";
|
||||
import { AppFile } from "../types/AppFile";
|
||||
import { FloatingButton } from "./FloatingButton";
|
||||
import { FileCollection } from "./FileCollection";
|
||||
import { DropZone } from "./DropZone";
|
||||
|
||||
type IProps = {
|
||||
files: AppFile[];
|
||||
};
|
||||
|
||||
export const FileList: FC<IProps> = ({ files }) => {
|
||||
return (
|
||||
<>
|
||||
<div className="row valign-wrapper">
|
||||
<h3>Files</h3>
|
||||
<FloatingButton color=" blue-grey lighten-4" size="" />
|
||||
</div>
|
||||
<DropZone />
|
||||
<FileCollection files={files} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
7
client/src/components/DropZone.tsx
Normal file
7
client/src/components/DropZone.tsx
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
import React, { FC } from "react";
|
||||
|
||||
type IProps = {};
|
||||
|
||||
export const DropZone: FC<IProps> = () => {
|
||||
return <div className="copy">Drag & Drop your files here.</div>;
|
||||
};
|
||||
38
client/src/components/FileCollection.tsx
Normal file
38
client/src/components/FileCollection.tsx
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
import React, { FC } from "react";
|
||||
import { AppFile } from "../types/AppFile";
|
||||
|
||||
type IProps = {
|
||||
files: AppFile[];
|
||||
};
|
||||
|
||||
export const FileCollection: FC<IProps> = ({ files }) => {
|
||||
return (
|
||||
<>
|
||||
<ul className="collection">
|
||||
{files.map((f: AppFile) => (
|
||||
<FileEntry file={f} />
|
||||
))}
|
||||
</ul>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
type IFProps = {
|
||||
file: AppFile;
|
||||
};
|
||||
|
||||
export const FileEntry: FC<IFProps> = ({ file }) => {
|
||||
return (
|
||||
<li key={file.id} 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>
|
||||
<p>
|
||||
{file.size}kb {file.format}
|
||||
</p>
|
||||
<a href="#!" className="secondary-content">
|
||||
<i className="material-icons">more_vert</i>
|
||||
</a>
|
||||
</li>
|
||||
);
|
||||
};
|
||||
55
client/src/components/Preloader.tsx
Normal file
55
client/src/components/Preloader.tsx
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
import React, { FC } from "react";
|
||||
|
||||
export const Preloader: FC = () => {
|
||||
return (
|
||||
<div className="preloader-wrapper big active">
|
||||
<div className="spinner-layer spinner-blue">
|
||||
<div className="circle-clipper left">
|
||||
<div className="circle"></div>
|
||||
</div>
|
||||
<div className="gap-patch">
|
||||
<div className="circle"></div>
|
||||
</div>
|
||||
<div className="circle-clipper right">
|
||||
<div className="circle"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="spinner-layer spinner-red">
|
||||
<div className="circle-clipper left">
|
||||
<div className="circle"></div>
|
||||
</div>
|
||||
<div className="gap-patch">
|
||||
<div className="circle"></div>
|
||||
</div>
|
||||
<div className="circle-clipper right">
|
||||
<div className="circle"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="spinner-layer spinner-yellow">
|
||||
<div className="circle-clipper left">
|
||||
<div className="circle"></div>
|
||||
</div>
|
||||
<div className="gap-patch">
|
||||
<div className="circle"></div>
|
||||
</div>
|
||||
<div className="circle-clipper right">
|
||||
<div className="circle"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="spinner-layer spinner-green">
|
||||
<div className="circle-clipper left">
|
||||
<div className="circle"></div>
|
||||
</div>
|
||||
<div className="gap-patch">
|
||||
<div className="circle"></div>
|
||||
</div>
|
||||
<div className="circle-clipper right">
|
||||
<div className="circle"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
@ -1,16 +1,28 @@
|
|||
import React, { FC } from "react";
|
||||
import { TabRouterHeader } from "./TabRouterHeader";
|
||||
import { TicketList } from "./TicketList";
|
||||
import { FileList } from "./AppFileList";
|
||||
import { Ticket } from "../types/Ticket";
|
||||
import { AppFile } from "../types/AppFile";
|
||||
import { Switch, Route, useRouteMatch, Redirect } from "react-router-dom";
|
||||
import { ActivityList } from "./ActivityList";
|
||||
import { Activity } from "../types/Activity";
|
||||
|
||||
interface IProps {
|
||||
tickets: Ticket[];
|
||||
remainingDays?: number;
|
||||
tabNames: string[];
|
||||
files: AppFile[];
|
||||
activities: Activity[];
|
||||
}
|
||||
|
||||
export const TabRouter: FC<IProps> = ({ tickets, remainingDays, tabNames }) => {
|
||||
export const TabRouter: FC<IProps> = ({
|
||||
tickets,
|
||||
remainingDays,
|
||||
tabNames,
|
||||
files,
|
||||
activities
|
||||
}) => {
|
||||
const { url } = useRouteMatch();
|
||||
return (
|
||||
<>
|
||||
|
|
@ -25,11 +37,11 @@ export const TabRouter: FC<IProps> = ({ tickets, remainingDays, tabNames }) => {
|
|||
</Route>
|
||||
|
||||
<Route path={`${url}/files`}>
|
||||
{/* <TicketList tickets={tickets} /> */}
|
||||
<FileList files={files} />
|
||||
</Route>
|
||||
|
||||
<Route path={`${url}/activity`}>
|
||||
{/* <TicketList tickets={tickets} /> */}
|
||||
<ActivityList activities={activities} />
|
||||
</Route>
|
||||
</div>
|
||||
</Switch>
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ export const TabRouterHeader: FC<IProps> = ({
|
|||
nTabs,
|
||||
tabNames
|
||||
}) => {
|
||||
const [isActive, setIsActive] = useState(0);
|
||||
const [isActive, setIsActive] = useState<number>(0);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -18,7 +18,9 @@ export const ProjectPage: FC<IProps> = ({ viewModel }) => {
|
|||
tickets,
|
||||
ticketsDone,
|
||||
ticketsTotalCount,
|
||||
remainingDays
|
||||
remainingDays,
|
||||
files,
|
||||
activities
|
||||
} = viewModel;
|
||||
const tabNames: string[] = ["Tickets", "Files", "Activity"];
|
||||
return (
|
||||
|
|
@ -38,7 +40,9 @@ export const ProjectPage: FC<IProps> = ({ viewModel }) => {
|
|||
<TabRouter
|
||||
tabNames={tabNames}
|
||||
tickets={tickets}
|
||||
files={files}
|
||||
remainingDays={remainingDays}
|
||||
activities={activities}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
10
client/src/types/Activity.ts
Normal file
10
client/src/types/Activity.ts
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
import { User } from "./User";
|
||||
import { Ticket } from "./Ticket";
|
||||
|
||||
export interface Activity {
|
||||
id: number;
|
||||
description: string;
|
||||
date: Date;
|
||||
user: User;
|
||||
ticket: Ticket;
|
||||
}
|
||||
9
client/src/types/AppFile.ts
Normal file
9
client/src/types/AppFile.ts
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
import { User } from "./User";
|
||||
|
||||
export interface AppFile {
|
||||
id: number;
|
||||
name: string;
|
||||
description: string;
|
||||
format: string;
|
||||
size: number;
|
||||
}
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
export interface File {
|
||||
Id: number;
|
||||
}
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
export interface History {
|
||||
Id: number;
|
||||
}
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
import { Ticket } from "./Ticket";
|
||||
import { User } from "./User";
|
||||
import { AppFile } from "./AppFile";
|
||||
import { Activity } from "./Activity";
|
||||
|
||||
export interface Project {
|
||||
id: number;
|
||||
|
|
@ -9,4 +11,6 @@ export interface Project {
|
|||
tickets: Ticket[];
|
||||
users: User[];
|
||||
plannedEnding: string;
|
||||
files: AppFile[];
|
||||
activities: Activity[];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
export interface User {
|
||||
id: string;
|
||||
picture: string;
|
||||
firstName: string;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ import { Ticket } from "../types/Ticket";
|
|||
import { Project } from "../types/Project";
|
||||
import { Constants } from "../utils/Constants";
|
||||
import { User } from "../types/User";
|
||||
import { AppFile } from "../types/AppFile";
|
||||
import { Activity } from "../types/Activity";
|
||||
|
||||
export default class ProjectVM {
|
||||
public id: number;
|
||||
|
|
@ -13,6 +15,8 @@ export default class ProjectVM {
|
|||
public ticketsTotalCount: number;
|
||||
public ticketsDone: number;
|
||||
public remainingDays: number;
|
||||
public files: AppFile[];
|
||||
public activities: Activity[];
|
||||
|
||||
/**
|
||||
* getMembers
|
||||
|
|
@ -34,13 +38,14 @@ export default class ProjectVM {
|
|||
this.tickets = project.tickets;
|
||||
this.ticketsTotalCount = this.tickets.length;
|
||||
this.ticketsDone = this.tickets.filter(t => t.status === "Done").length;
|
||||
this.files = project.files;
|
||||
this.activities = project.activities;
|
||||
|
||||
let endingDate: Date = new Date(project.plannedEnding);
|
||||
let today: Date = new Date();
|
||||
let plannedEnding: number = Math.abs(
|
||||
endingDate.getDate() - today.getDate()
|
||||
);
|
||||
|
||||
this.remainingDays = plannedEnding;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue