mirror of
https://github.com/rjNemo/ticket_manager
synced 2026-06-12 11:46:40 +00:00
handled project selector in newticketform
This commit is contained in:
parent
ec53a6edb6
commit
61d189b3d3
16 changed files with 97 additions and 35 deletions
|
|
@ -1,7 +1,3 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
|
|
|
||||||
|
|
@ -50,3 +50,4 @@
|
||||||
- [<span style="color:red">X</span>] write dtos without circular dependencies.
|
- [<span style="color:red">X</span>] write dtos without circular dependencies.
|
||||||
- [ ] use dtoRequest for PutProjects
|
- [ ] use dtoRequest for PutProjects
|
||||||
- [ ] render avatarlist after UserModal Update
|
- [ ] render avatarlist after UserModal Update
|
||||||
|
- [ ] Form validators
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,11 @@ namespace TicketManager.Resources
|
||||||
{
|
{
|
||||||
public class NewAppUserDTO
|
public class NewAppUserDTO
|
||||||
{
|
{
|
||||||
|
[Required]
|
||||||
public string FirstName { get; set; }
|
public string FirstName { get; set; }
|
||||||
public string LastName { get; set; }
|
public string LastName { get; set; }
|
||||||
public string Presentation { get; set; }
|
public string Presentation { get; set; }
|
||||||
|
[Required]
|
||||||
[DataType(DataType.EmailAddress)]
|
[DataType(DataType.EmailAddress)]
|
||||||
public string Email { get; set; }
|
public string Email { get; set; }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,9 @@ namespace TicketManager.Resources
|
||||||
[Required]
|
[Required]
|
||||||
public string Title { get; set; }
|
public string Title { get; set; }
|
||||||
public string Description { get; set; }
|
public string Description { get; set; }
|
||||||
|
[Required]
|
||||||
public DateTime EndingDate { get; set; }
|
public DateTime EndingDate { get; set; }
|
||||||
|
[Required]
|
||||||
public Guid ManagerId { get; set; }
|
public Guid ManagerId { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -8,10 +8,11 @@ namespace TicketManager.Resources
|
||||||
{
|
{
|
||||||
public class NewTicketDTO
|
public class NewTicketDTO
|
||||||
{
|
{
|
||||||
|
[Required]
|
||||||
public string Title { get; set; }
|
public string Title { get; set; }
|
||||||
|
[Required]
|
||||||
public string Description { get; set; }
|
public string Description { get; set; }
|
||||||
|
[Required]
|
||||||
[DataType(DataType.Date)]
|
[DataType(DataType.Date)]
|
||||||
public DateTime EndingDate { get; set; }
|
public DateTime EndingDate { get; set; }
|
||||||
|
|
||||||
|
|
@ -20,8 +21,9 @@ namespace TicketManager.Resources
|
||||||
public string Difficulty { get; set; }
|
public string Difficulty { get; set; }
|
||||||
|
|
||||||
public string Category { get; set; }
|
public string Category { get; set; }
|
||||||
|
[Required]
|
||||||
public Guid CreatorId { get; set; }
|
public Guid CreatorId { get; set; }
|
||||||
|
[Required]
|
||||||
public int ProjectId { get; set; }
|
public int ProjectId { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -6,7 +6,7 @@ import { User } from "../types/User";
|
||||||
import { getRemainingdays } from "../utils/methods";
|
import { getRemainingdays } from "../utils/methods";
|
||||||
|
|
||||||
export default class ProjectVM {
|
export default class ProjectVM {
|
||||||
// public id: number;
|
public id: number;
|
||||||
public title: string;
|
public title: string;
|
||||||
public description: string;
|
public description: string;
|
||||||
public creationDate: string;
|
public creationDate: string;
|
||||||
|
|
@ -22,9 +22,14 @@ export default class ProjectVM {
|
||||||
public ticketsTotalCount: number;
|
public ticketsTotalCount: number;
|
||||||
public ticketsDone: number;
|
public ticketsDone: number;
|
||||||
public remainingDays: number;
|
public remainingDays: number;
|
||||||
|
public allProjects: Project[];
|
||||||
|
|
||||||
public constructor(project: Project, allUsers: User[]) {
|
public constructor(
|
||||||
// this.id = project.id;
|
project: Project,
|
||||||
|
allUsers: User[],
|
||||||
|
allProjects: Project[]
|
||||||
|
) {
|
||||||
|
this.id = project.id;
|
||||||
this.title = project.title;
|
this.title = project.title;
|
||||||
this.description = project.description;
|
this.description = project.description;
|
||||||
this.creationDate = project.creationDate;
|
this.creationDate = project.creationDate;
|
||||||
|
|
@ -44,5 +49,6 @@ export default class ProjectVM {
|
||||||
? 0
|
? 0
|
||||||
: this.tickets.filter(t => t.status === "Done").length;
|
: this.tickets.filter(t => t.status === "Done").length;
|
||||||
this.remainingDays = getRemainingdays(project.endingDate);
|
this.remainingDays = getRemainingdays(project.endingDate);
|
||||||
|
this.allProjects = allProjects;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,13 @@ interface IProps {
|
||||||
export const Avatar: FC<IProps> = ({ picture }) => {
|
export const Avatar: FC<IProps> = ({ picture }) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<img className="circle" src={picture} height="100vh" width="100vh" />
|
<img
|
||||||
|
className="circle"
|
||||||
|
src={picture}
|
||||||
|
height="100vh"
|
||||||
|
width="100vh"
|
||||||
|
alt="user avatar"
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import React, { FC } from "react";
|
import React, { FC } from "react";
|
||||||
|
import { Project } from "../types/Project";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
title: string;
|
title: string;
|
||||||
|
|
@ -7,6 +8,9 @@ interface IProps {
|
||||||
setDescription: React.Dispatch<React.SetStateAction<string>>;
|
setDescription: React.Dispatch<React.SetStateAction<string>>;
|
||||||
endingDate: string;
|
endingDate: string;
|
||||||
setEndingDate: React.Dispatch<React.SetStateAction<string>>;
|
setEndingDate: React.Dispatch<React.SetStateAction<string>>;
|
||||||
|
allProjects: Project[];
|
||||||
|
projectId: string;
|
||||||
|
setProjectId: React.Dispatch<React.SetStateAction<string>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const NewTicketForm: FC<IProps> = ({
|
export const NewTicketForm: FC<IProps> = ({
|
||||||
|
|
@ -15,7 +19,10 @@ export const NewTicketForm: FC<IProps> = ({
|
||||||
description,
|
description,
|
||||||
setDescription,
|
setDescription,
|
||||||
endingDate,
|
endingDate,
|
||||||
setEndingDate
|
setEndingDate,
|
||||||
|
allProjects,
|
||||||
|
projectId,
|
||||||
|
setProjectId
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
@ -62,13 +69,23 @@ export const NewTicketForm: FC<IProps> = ({
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="input-field">
|
<div className="input-field">
|
||||||
<select id="project" className="browser-default">
|
<select
|
||||||
<option value="" disabled selected>
|
id="project"
|
||||||
|
className="browser-default"
|
||||||
|
value={projectId}
|
||||||
|
onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
|
||||||
|
e.preventDefault();
|
||||||
|
setProjectId(e.target.value);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<option value={0} disabled>
|
||||||
Project
|
Project
|
||||||
</option>
|
</option>
|
||||||
<option value="1">Option 1</option>
|
{allProjects.map(p => (
|
||||||
<option value="2">Option 2</option>
|
<option key={p.id} value={p.id}>
|
||||||
<option value="3">Option 3</option>
|
{p.title}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -5,16 +5,23 @@ import { post } from "../utils/http";
|
||||||
import { Constants } from "../utils/Constants";
|
import { Constants } from "../utils/Constants";
|
||||||
import { HttpResponse } from "../types/HttpResponse";
|
import { HttpResponse } from "../types/HttpResponse";
|
||||||
import { NewTicketForm } from "./NewTicketForm";
|
import { NewTicketForm } from "./NewTicketForm";
|
||||||
|
import { Project } from "../types/Project";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
show: boolean;
|
show: boolean;
|
||||||
handleClose(): void;
|
handleClose(): void;
|
||||||
|
allProjects: Project[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const NewTicketModal: FC<IProps> = ({ show, handleClose }) => {
|
export const NewTicketModal: FC<IProps> = ({
|
||||||
|
show,
|
||||||
|
handleClose,
|
||||||
|
allProjects
|
||||||
|
}) => {
|
||||||
const [title, setTitle] = useState("");
|
const [title, setTitle] = useState("");
|
||||||
const [description, setDescription] = useState("");
|
const [description, setDescription] = useState("");
|
||||||
const [endingDate, setEndingDate] = useState("");
|
const [endingDate, setEndingDate] = useState("");
|
||||||
|
const [projectId, setProjectId] = useState("0");
|
||||||
|
|
||||||
const handleSubmit: (event: FormEvent<HTMLFormElement>) => void = async (
|
const handleSubmit: (event: FormEvent<HTMLFormElement>) => void = async (
|
||||||
e: FormEvent
|
e: FormEvent
|
||||||
|
|
@ -25,7 +32,7 @@ export const NewTicketModal: FC<IProps> = ({ show, handleClose }) => {
|
||||||
description: description,
|
description: description,
|
||||||
endingDate: new Date(endingDate).toISOString(),
|
endingDate: new Date(endingDate).toISOString(),
|
||||||
creatorId: "20bf4b2a-7209-4826-96cd-29c2bc937a94",
|
creatorId: "20bf4b2a-7209-4826-96cd-29c2bc937a94",
|
||||||
projectId: 1
|
projectId: parseInt(projectId)
|
||||||
};
|
};
|
||||||
// console.log(newTicket);
|
// console.log(newTicket);
|
||||||
const response: HttpResponse<Ticket> = await post<Ticket>(
|
const response: HttpResponse<Ticket> = await post<Ticket>(
|
||||||
|
|
@ -63,6 +70,9 @@ export const NewTicketModal: FC<IProps> = ({ show, handleClose }) => {
|
||||||
setDescription={setDescription}
|
setDescription={setDescription}
|
||||||
endingDate={endingDate}
|
endingDate={endingDate}
|
||||||
setEndingDate={setEndingDate}
|
setEndingDate={setEndingDate}
|
||||||
|
allProjects={allProjects}
|
||||||
|
projectId={projectId}
|
||||||
|
setProjectId={setProjectId}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
import React, { FC } from "react";
|
import React, { FC } from "react";
|
||||||
import { useRouteMatch } from "react-router-dom";
|
import { useRouteMatch } from "react-router-dom";
|
||||||
import { TabRouterHeader } from "./TabRouterHeader";
|
import { TabRouterHeader } from "./TabRouterHeader";
|
||||||
import { NewTicketForm } from "./NewTicketForm";
|
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
tabNames: string[];
|
tabNames: string[];
|
||||||
|
|
@ -28,14 +27,14 @@ export const NewTicketTabRouter: FC<IProps> = ({
|
||||||
<div className="row">
|
<div className="row">
|
||||||
<TabRouterHeader tabNames={tabNames} />
|
<TabRouterHeader tabNames={tabNames} />
|
||||||
|
|
||||||
<NewTicketForm
|
{/* <NewTicketForm
|
||||||
title={title}
|
title={title}
|
||||||
setTitle={setTitle}
|
setTitle={setTitle}
|
||||||
description={description}
|
description={description}
|
||||||
setDescription={setDescription}
|
setDescription={setDescription}
|
||||||
endingDate={endingDate}
|
endingDate={endingDate}
|
||||||
setEndingDate={setEndingDate}
|
setEndingDate={setEndingDate}
|
||||||
/>
|
/> */}
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import { FileList } from "./AppFileList";
|
||||||
import { Ticket } from "../types/Ticket";
|
import { Ticket } from "../types/Ticket";
|
||||||
import { AppFile } from "../types/AppFile";
|
import { AppFile } from "../types/AppFile";
|
||||||
import { Activity } from "../types/Activity";
|
import { Activity } from "../types/Activity";
|
||||||
|
import { Project } from "../types/Project";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
tickets: Ticket[];
|
tickets: Ticket[];
|
||||||
|
|
@ -14,13 +15,15 @@ interface IProps {
|
||||||
tabNames: string[];
|
tabNames: string[];
|
||||||
files: AppFile[];
|
files: AppFile[];
|
||||||
activities: Activity[];
|
activities: Activity[];
|
||||||
|
allProjects: Project[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const TabRouter: FC<IProps> = ({
|
export const TabRouter: FC<IProps> = ({
|
||||||
tickets,
|
tickets,
|
||||||
tabNames,
|
tabNames,
|
||||||
files,
|
files,
|
||||||
activities
|
activities,
|
||||||
|
allProjects
|
||||||
}) => {
|
}) => {
|
||||||
const { url } = useRouteMatch();
|
const { url } = useRouteMatch();
|
||||||
|
|
||||||
|
|
@ -32,7 +35,7 @@ export const TabRouter: FC<IProps> = ({
|
||||||
<Redirect from={url} to={`${url}/tickets`} />
|
<Redirect from={url} to={`${url}/tickets`} />
|
||||||
|
|
||||||
<Route path={`${url}/tickets`}>
|
<Route path={`${url}/tickets`}>
|
||||||
<TicketList tickets={tickets} />
|
<TicketList tickets={tickets} allProjects={allProjects} />
|
||||||
</Route>
|
</Route>
|
||||||
|
|
||||||
<Route path={`${url}/files`}>
|
<Route path={`${url}/files`}>
|
||||||
|
|
|
||||||
|
|
@ -7,12 +7,14 @@ import { HttpResponse } from "../types/HttpResponse";
|
||||||
import { put } from "../utils/http";
|
import { put } from "../utils/http";
|
||||||
import { Constants } from "../utils/Constants";
|
import { Constants } from "../utils/Constants";
|
||||||
import { NewTicketModal } from "./NewTicketModal";
|
import { NewTicketModal } from "./NewTicketModal";
|
||||||
|
import { Project } from "../types/Project";
|
||||||
|
|
||||||
type TicketListProps = {
|
type TicketListProps = {
|
||||||
tickets: Ticket[];
|
tickets: Ticket[];
|
||||||
|
allProjects: Project[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export const TicketList: FC<TicketListProps> = ({ tickets }) => {
|
export const TicketList: FC<TicketListProps> = ({ tickets, allProjects }) => {
|
||||||
const [filterText, setFilterText] = useState<string>("");
|
const [filterText, setFilterText] = useState<string>("");
|
||||||
const clearFilterText: (e: MouseEvent) => void = (e: MouseEvent) => {
|
const clearFilterText: (e: MouseEvent) => void = (e: MouseEvent) => {
|
||||||
setFilterText("");
|
setFilterText("");
|
||||||
|
|
@ -42,6 +44,7 @@ export const TicketList: FC<TicketListProps> = ({ tickets }) => {
|
||||||
setShowNew(false);
|
setShowNew(false);
|
||||||
}}
|
}}
|
||||||
show={showNew}
|
show={showNew}
|
||||||
|
allProjects={allProjects}
|
||||||
/>
|
/>
|
||||||
<h3>Tickets</h3>
|
<h3>Tickets</h3>
|
||||||
<FloatingButton
|
<FloatingButton
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import { TabRouterHeader } from "./TabRouterHeader";
|
||||||
import { ProjectList } from "./ProjectList";
|
import { ProjectList } from "./ProjectList";
|
||||||
import { Ticket } from "../types/Ticket";
|
import { Ticket } from "../types/Ticket";
|
||||||
import { Project } from "../types/Project";
|
import { Project } from "../types/Project";
|
||||||
|
import { TicketList } from "./TicketList";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
tabNames: string[];
|
tabNames: string[];
|
||||||
|
|
@ -25,9 +26,9 @@ export const UserTabRouter: FC<IProps> = ({ tickets, tabNames, projects }) => {
|
||||||
<ProjectList projects={projects} />
|
<ProjectList projects={projects} />
|
||||||
</Route>
|
</Route>
|
||||||
|
|
||||||
{/* <Route path={`${url}/tickets`}>
|
<Route path={`${url}/tickets`}>
|
||||||
<TicketList tickets={tickets} />
|
<TicketList tickets={tickets} allProjects={[]} />
|
||||||
</Route> */}
|
</Route>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ import { User } from "../types/User";
|
||||||
export const ProjectController: FC = () => {
|
export const ProjectController: FC = () => {
|
||||||
const [project, setProject] = useState<Project>({} as Project);
|
const [project, setProject] = useState<Project>({} as Project);
|
||||||
const [allUsers, setAllUsers] = useState<User[]>([]);
|
const [allUsers, setAllUsers] = useState<User[]>([]);
|
||||||
|
const [allProjects, setAllProjects] = useState<Project[]>([]);
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
const [hasError, setHasError] = useState(false);
|
const [hasError, setHasError] = useState(false);
|
||||||
const [error, setError] = useState("");
|
const [error, setError] = useState("");
|
||||||
|
|
@ -48,10 +49,25 @@ export const ProjectController: FC = () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function httpGetAllProjects(): Promise<void> {
|
||||||
|
try {
|
||||||
|
const response: HttpResponse<Project> = await get<Project>(
|
||||||
|
`${Constants.projectsURI}`
|
||||||
|
);
|
||||||
|
if (response.parsedBody !== undefined) {
|
||||||
|
setAllProjects((response.parsedBody as unknown) as Project[]);
|
||||||
|
}
|
||||||
|
} catch (ex) {
|
||||||
|
setHasError(true);
|
||||||
|
setError(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (id !== undefined) {
|
if (id !== undefined) {
|
||||||
httpGetProjects(id);
|
httpGetProjects(id);
|
||||||
httpGetAllUsers();
|
httpGetAllUsers();
|
||||||
|
httpGetAllProjects();
|
||||||
} else {
|
} else {
|
||||||
setHasError(true);
|
setHasError(true);
|
||||||
setError("Bad Request");
|
setError("Bad Request");
|
||||||
|
|
@ -61,6 +77,6 @@ export const ProjectController: FC = () => {
|
||||||
if (hasError) {
|
if (hasError) {
|
||||||
return <ErrorController error={error} />;
|
return <ErrorController error={error} />;
|
||||||
}
|
}
|
||||||
const viewModel = new ProjectVM(project, allUsers);
|
const viewModel = new ProjectVM(project, allUsers, allProjects);
|
||||||
return isLoading ? <Preloader /> : <ProjectPage viewModel={viewModel} />;
|
return isLoading ? <Preloader /> : <ProjectPage viewModel={viewModel} />;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ interface IProps {
|
||||||
|
|
||||||
export const ProjectPage: FC<IProps> = ({ viewModel }) => {
|
export const ProjectPage: FC<IProps> = ({ viewModel }) => {
|
||||||
const {
|
const {
|
||||||
|
// id,
|
||||||
title,
|
title,
|
||||||
description,
|
description,
|
||||||
users,
|
users,
|
||||||
|
|
@ -23,7 +24,8 @@ export const ProjectPage: FC<IProps> = ({ viewModel }) => {
|
||||||
ticketsTotalCount,
|
ticketsTotalCount,
|
||||||
remainingDays,
|
remainingDays,
|
||||||
files,
|
files,
|
||||||
activities
|
activities,
|
||||||
|
allProjects
|
||||||
} = viewModel;
|
} = viewModel;
|
||||||
|
|
||||||
const tabNames: string[] = ["Tickets", "Files"]; //, "Activity"];
|
const tabNames: string[] = ["Tickets", "Files"]; //, "Activity"];
|
||||||
|
|
@ -59,6 +61,7 @@ export const ProjectPage: FC<IProps> = ({ viewModel }) => {
|
||||||
tickets={tickets}
|
tickets={tickets}
|
||||||
files={files}
|
files={files}
|
||||||
activities={activities}
|
activities={activities}
|
||||||
|
allProjects={allProjects}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -23,10 +23,6 @@ export const UserPage: FC<IProps> = ({ viewModel }) => {
|
||||||
tickets={tickets}
|
tickets={tickets}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{/* // <TabView>
|
|
||||||
// <CardList>
|
|
||||||
// <CardList>
|
|
||||||
// </TabView> */}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue