mirror of
https://github.com/rjNemo/ticket_manager
synced 2026-06-12 11:46:40 +00:00
update InputFile; AppFileList
This commit is contained in:
parent
70d1df1e05
commit
12a8e9e289
6 changed files with 252 additions and 95 deletions
|
|
@ -3,6 +3,7 @@ import { AppFile } from "../types/AppFile";
|
||||||
import { FileCollection } from "./FileCollection";
|
import { FileCollection } from "./FileCollection";
|
||||||
import { InputFile } from "./InputFile";
|
import { InputFile } from "./InputFile";
|
||||||
import { FilterBar } from "./FilterBar";
|
import { FilterBar } from "./FilterBar";
|
||||||
|
import { Grid, Typography } from "@material-ui/core";
|
||||||
|
|
||||||
type IProps = {
|
type IProps = {
|
||||||
files: AppFile[];
|
files: AppFile[];
|
||||||
|
|
@ -18,14 +19,20 @@ export const FileList: FC<IProps> = ({ files }) => {
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="row valign-wrapper">
|
<Grid container>
|
||||||
<h3>Files</h3>
|
<Grid item xs>
|
||||||
<FilterBar
|
<Typography variant="h4" component="h4">
|
||||||
filterText={filterText}
|
Files
|
||||||
handleChange={handleChange}
|
</Typography>
|
||||||
clearFilterText={clearFilterText}
|
</Grid>
|
||||||
/>
|
<Grid item xs={4}>
|
||||||
</div>
|
<FilterBar
|
||||||
|
filterText={filterText}
|
||||||
|
handleChange={handleChange}
|
||||||
|
clearFilterText={clearFilterText}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
<InputFile />
|
<InputFile />
|
||||||
<FileCollection files={files} filterText={filterText} />
|
<FileCollection files={files} filterText={filterText} />
|
||||||
</>
|
</>
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ export const AvatarList: FC<AvatarListProps> = ({ users }) => {
|
||||||
<></>
|
<></>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<AvatarGroup max={2}>
|
<AvatarGroup max={5}>
|
||||||
{users.map((user: User, i: number) => (
|
{users.map((user: User, i: number) => (
|
||||||
<Link to={`/users/${user.id}`} key={i}>
|
<Link to={`/users/${user.id}`} key={i}>
|
||||||
<Avatar src={user.picture} alt={user.fullName} />
|
<Avatar src={user.picture} alt={user.fullName} />
|
||||||
|
|
|
||||||
|
|
@ -1,27 +1,62 @@
|
||||||
import React, { FC } from "react";
|
import React, { FC } from "react";
|
||||||
|
import { CloudUpload } from "@material-ui/icons";
|
||||||
|
import { makeStyles, createStyles, Theme } from "@material-ui/core/styles";
|
||||||
|
import Button from "@material-ui/core/Button";
|
||||||
|
|
||||||
export const InputFile: FC = () => {
|
export const InputFile: FC = () => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<form action="/upload">
|
<form action="/upload">
|
||||||
<div className="file-field input-field">
|
<div className="file-field input-field">
|
||||||
<div className="btn indigo lighten-1">
|
<UploadButton>
|
||||||
<i className="material-icons ">cloud_upload</i>
|
<CloudUpload />
|
||||||
<input
|
<input
|
||||||
type="file"
|
type="file"
|
||||||
multiple
|
multiple
|
||||||
accept=".doc,.docx,.pdf,.md,.gdoc,.zip,image/*"
|
accept=".doc,.docx,.pdf,.md,.gdoc,.zip,image/*"
|
||||||
/>
|
/>
|
||||||
</div>
|
</UploadButton>
|
||||||
<div className="file-path-wrapper">
|
|
||||||
<input
|
|
||||||
className="file-path validate"
|
|
||||||
type="text"
|
|
||||||
placeholder="Upload one or more files"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const useStyles = makeStyles((theme: Theme) =>
|
||||||
|
createStyles({
|
||||||
|
root: {
|
||||||
|
"& > *": {
|
||||||
|
margin: theme.spacing(1)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
input: {
|
||||||
|
display: "none"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
const UploadButton: FC = () => {
|
||||||
|
const classes = useStyles();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classes.root}>
|
||||||
|
<input
|
||||||
|
accept=".doc,.docx,.pdf,.md,.gdoc,.zip,image/*"
|
||||||
|
className={classes.input}
|
||||||
|
id="contained-button-file"
|
||||||
|
multiple
|
||||||
|
type="file"
|
||||||
|
/>
|
||||||
|
<label htmlFor="contained-button-file">
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
color="primary"
|
||||||
|
component="span"
|
||||||
|
startIcon={<CloudUpload />}
|
||||||
|
>
|
||||||
|
Upload files
|
||||||
|
</Button>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
|
||||||
110
client/src/components/ProjectTabPanel.tsx
Normal file
110
client/src/components/ProjectTabPanel.tsx
Normal file
|
|
@ -0,0 +1,110 @@
|
||||||
|
import React, { FC } from "react";
|
||||||
|
import SwipeableViews from "react-swipeable-views";
|
||||||
|
import { makeStyles, Theme, useTheme } from "@material-ui/core/styles";
|
||||||
|
import AppBar from "@material-ui/core/AppBar";
|
||||||
|
import Tabs from "@material-ui/core/Tabs";
|
||||||
|
import Tab from "@material-ui/core/Tab";
|
||||||
|
import Typography from "@material-ui/core/Typography";
|
||||||
|
import Box from "@material-ui/core/Box";
|
||||||
|
import { Ticket } from "../types/Ticket";
|
||||||
|
import { Project } from "../types/Project";
|
||||||
|
import { FileList } from "./AppFileList";
|
||||||
|
import { TicketList } from "./TicketList";
|
||||||
|
import { AppFile } from "../types/AppFile";
|
||||||
|
|
||||||
|
interface TabProps {
|
||||||
|
children?: React.ReactNode;
|
||||||
|
dir?: string;
|
||||||
|
index: any;
|
||||||
|
value: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TabPanel: FC<TabProps> = (props: TabProps) => {
|
||||||
|
const { children, value, index, ...other } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Typography
|
||||||
|
component="div"
|
||||||
|
role="tabpanel"
|
||||||
|
hidden={value !== index}
|
||||||
|
id={`full-width-tabpanel-${index}`}
|
||||||
|
aria-labelledby={`full-width-tab-${index}`}
|
||||||
|
{...other}
|
||||||
|
>
|
||||||
|
{value === index && <Box p={3}>{children}</Box>}
|
||||||
|
</Typography>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const a11yProps = (index: any) => {
|
||||||
|
return {
|
||||||
|
id: `full-width-tab-${index}`,
|
||||||
|
"aria-controls": `full-width-tabpanel-${index}`
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const useStyles = makeStyles((theme: Theme) => ({
|
||||||
|
root: {
|
||||||
|
backgroundColor: "#ffffff",
|
||||||
|
flexGrow: 1
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
tickets: Ticket[];
|
||||||
|
remainingDays?: number;
|
||||||
|
tabNames: string[];
|
||||||
|
files: AppFile[];
|
||||||
|
// activities: Activity[];
|
||||||
|
allProjects: Project[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ProjectTabPanel: FC<IProps> = ({
|
||||||
|
tickets,
|
||||||
|
tabNames,
|
||||||
|
files
|
||||||
|
// allProjects
|
||||||
|
}) => {
|
||||||
|
const classes = useStyles();
|
||||||
|
const theme = useTheme();
|
||||||
|
const [value, setValue] = React.useState(0);
|
||||||
|
|
||||||
|
const handleChange = (event: React.ChangeEvent<{}>, newValue: number) => {
|
||||||
|
setValue(newValue);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleChangeIndex = (index: number) => {
|
||||||
|
setValue(index);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classes.root}>
|
||||||
|
<AppBar position="static" color="inherit">
|
||||||
|
<Tabs
|
||||||
|
value={value}
|
||||||
|
onChange={handleChange}
|
||||||
|
indicatorColor="primary"
|
||||||
|
textColor="primary"
|
||||||
|
variant="fullWidth"
|
||||||
|
aria-label="full width tabs example"
|
||||||
|
>
|
||||||
|
{tabNames.map((t: string, i: number) => (
|
||||||
|
<Tab key={i} label={t} {...a11yProps({ i })} />
|
||||||
|
))}
|
||||||
|
</Tabs>
|
||||||
|
</AppBar>
|
||||||
|
<SwipeableViews
|
||||||
|
axis={theme.direction === "rtl" ? "x-reverse" : "x"}
|
||||||
|
index={value}
|
||||||
|
onChangeIndex={handleChangeIndex}
|
||||||
|
>
|
||||||
|
<TabPanel value={value} index={0} dir={theme.direction}>
|
||||||
|
<TicketList tickets={tickets} allProjects={[]} addButton={false} />
|
||||||
|
</TabPanel>
|
||||||
|
<TabPanel value={value} index={1} dir={theme.direction}>
|
||||||
|
<FileList files={files} />
|
||||||
|
</TabPanel>
|
||||||
|
</SwipeableViews>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
@ -42,58 +42,56 @@ export const TicketList: FC<TicketListProps> = ({
|
||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="row valign-wrapper">
|
<NewTicketModal
|
||||||
<NewTicketModal
|
handleClose={() => {
|
||||||
handleClose={() => {
|
setShowNew(false);
|
||||||
setShowNew(false);
|
}}
|
||||||
}}
|
show={showNew}
|
||||||
show={showNew}
|
allProjects={allProjects}
|
||||||
allProjects={allProjects}
|
/>
|
||||||
/>
|
|
||||||
|
|
||||||
<Grid container>
|
<Grid container>
|
||||||
<Grid item xs>
|
<Grid item xs>
|
||||||
<Typography variant="h4" component="h4">
|
<Typography variant="h4" component="h4">
|
||||||
Tickets
|
Tickets
|
||||||
</Typography>
|
</Typography>
|
||||||
</Grid>
|
|
||||||
<Grid item xs>
|
|
||||||
{addButton && (
|
|
||||||
<FloatingButton color="primary" size="small" onClick={onClick} />
|
|
||||||
)}
|
|
||||||
</Grid>
|
|
||||||
<Grid item xs={4}>
|
|
||||||
<FilterBar
|
|
||||||
filterText={filterText}
|
|
||||||
handleChange={handleChange}
|
|
||||||
clearFilterText={clearFilterText}
|
|
||||||
/>
|
|
||||||
</Grid>
|
|
||||||
<Grid item xs={12}>
|
|
||||||
<div className="col s12 grey lighten-1">
|
|
||||||
{filteredTickets.length === 0 ? (
|
|
||||||
<HorizontalCard />
|
|
||||||
) : (
|
|
||||||
filteredTickets.map((t: Ticket) => (
|
|
||||||
<HorizontalCard
|
|
||||||
key={t.id}
|
|
||||||
title={t.title}
|
|
||||||
remainingDays={t.endingDate}
|
|
||||||
link={`/tickets/${t.id}`}
|
|
||||||
validateTicket={async (e: MouseEvent) => {
|
|
||||||
e.preventDefault();
|
|
||||||
await put<HttpResponse<Ticket>>(
|
|
||||||
`${Constants.ticketsURI}/${t.id}/closed`,
|
|
||||||
{}
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
))
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</div>
|
<Grid item xs>
|
||||||
|
{addButton && (
|
||||||
|
<FloatingButton color="primary" size="small" onClick={onClick} />
|
||||||
|
)}
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={4}>
|
||||||
|
<FilterBar
|
||||||
|
filterText={filterText}
|
||||||
|
handleChange={handleChange}
|
||||||
|
clearFilterText={clearFilterText}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={12}>
|
||||||
|
<div className="col s12 grey lighten-1">
|
||||||
|
{filteredTickets.length === 0 ? (
|
||||||
|
<HorizontalCard />
|
||||||
|
) : (
|
||||||
|
filteredTickets.map((t: Ticket) => (
|
||||||
|
<HorizontalCard
|
||||||
|
key={t.id}
|
||||||
|
title={t.title}
|
||||||
|
remainingDays={t.endingDate}
|
||||||
|
link={`/tickets/${t.id}`}
|
||||||
|
validateTicket={async (e: MouseEvent) => {
|
||||||
|
e.preventDefault();
|
||||||
|
await put<HttpResponse<Ticket>>(
|
||||||
|
`${Constants.ticketsURI}/${t.id}/closed`,
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,8 @@ import { ProgressBar } from "../components/ProgressBar";
|
||||||
import { TabRouter } from "../components/TabRouter";
|
import { TabRouter } from "../components/TabRouter";
|
||||||
import { FloatingButton } from "../components/FloatingButton";
|
import { FloatingButton } from "../components/FloatingButton";
|
||||||
import { UsersModal } from "../components/UsersModal";
|
import { UsersModal } from "../components/UsersModal";
|
||||||
|
import { Container, Grid } from "@material-ui/core";
|
||||||
|
import { ProjectTabPanel } from "../components/ProjectTabPanel";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
viewModel: ProjectVM;
|
viewModel: ProjectVM;
|
||||||
|
|
@ -32,38 +34,43 @@ export const ProjectPage: FC<IProps> = ({ viewModel }) => {
|
||||||
const [showModal, setShowModal] = useState<boolean>(false);
|
const [showModal, setShowModal] = useState<boolean>(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="section">
|
<Container maxWidth="md">
|
||||||
<div className="container">
|
<Header title={title} description={description} />
|
||||||
<Header title={title} description={description} />
|
<UsersModal
|
||||||
<div className="row valign-wrapper">
|
show={showModal}
|
||||||
|
users={users}
|
||||||
|
allUsers={allUsers}
|
||||||
|
handleClose={() => setShowModal(false)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Grid container>
|
||||||
|
<Grid item xs={3}>
|
||||||
<AvatarList users={users} />
|
<AvatarList users={users} />
|
||||||
|
</Grid>
|
||||||
|
<Grid item xs={9}>
|
||||||
<FloatingButton
|
<FloatingButton
|
||||||
icon="add"
|
icon="add"
|
||||||
color="default"
|
color="default"
|
||||||
size="small"
|
size="small"
|
||||||
onClick={() => setShowModal(true)}
|
onClick={() => setShowModal(true)}
|
||||||
/>
|
/>
|
||||||
<UsersModal
|
</Grid>
|
||||||
show={showModal}
|
</Grid>
|
||||||
users={users}
|
|
||||||
allUsers={allUsers}
|
<ProgressBar
|
||||||
handleClose={() => setShowModal(false)}
|
value={progression}
|
||||||
/>
|
tasksDone={ticketsDone}
|
||||||
</div>
|
tasksTotalCount={ticketsTotalCount}
|
||||||
<ProgressBar
|
remainingDays={remainingDays}
|
||||||
value={progression}
|
/>
|
||||||
tasksDone={ticketsDone}
|
|
||||||
tasksTotalCount={ticketsTotalCount}
|
<ProjectTabPanel
|
||||||
remainingDays={remainingDays}
|
tabNames={tabNames}
|
||||||
/>
|
tickets={tickets}
|
||||||
<TabRouter
|
files={files}
|
||||||
tabNames={tabNames}
|
// activities={activities}
|
||||||
tickets={tickets}
|
allProjects={allProjects}
|
||||||
files={files}
|
/>
|
||||||
activities={activities}
|
</Container>
|
||||||
allProjects={allProjects}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue