mirror of
https://github.com/rjNemo/ticket_manager
synced 2026-06-06 00:36:39 +00:00
UI project page
This commit is contained in:
parent
9e47a6e1d8
commit
4710f0a551
16 changed files with 811 additions and 243 deletions
124
Controllers/AssignmentsController.cs
Normal file
124
Controllers/AssignmentsController.cs
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using TicketManager.Data;
|
||||
using TicketManager.Models;
|
||||
|
||||
namespace TicketManager.Controllers
|
||||
{
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
public class AssignmentsController : ControllerBase
|
||||
{
|
||||
private readonly AppDbContext _context;
|
||||
|
||||
public AssignmentsController(AppDbContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
// GET: api/Assignments
|
||||
[HttpGet]
|
||||
public async Task<ActionResult<IEnumerable<Assignment>>> GetAssignments()
|
||||
{
|
||||
return await _context.Assignments.ToListAsync();
|
||||
}
|
||||
|
||||
// GET: api/Assignments/5
|
||||
[HttpGet("{id}")]
|
||||
public async Task<ActionResult<Assignment>> GetAssignment(int id)
|
||||
{
|
||||
var assignment = await _context.Assignments.FindAsync(id);
|
||||
|
||||
if (assignment == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
return assignment;
|
||||
}
|
||||
|
||||
// PUT: api/Assignments/5
|
||||
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
|
||||
// more details see https://aka.ms/RazorPagesCRUD.
|
||||
[HttpPut("{id}")]
|
||||
public async Task<IActionResult> PutAssignment(int id, Assignment assignment)
|
||||
{
|
||||
if (id != assignment.ProjectId)
|
||||
{
|
||||
return BadRequest();
|
||||
}
|
||||
|
||||
_context.Entry(assignment).State = EntityState.Modified;
|
||||
|
||||
try
|
||||
{
|
||||
await _context.SaveChangesAsync();
|
||||
}
|
||||
catch (DbUpdateConcurrencyException)
|
||||
{
|
||||
if (!AssignmentExists(id))
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
return NoContent();
|
||||
}
|
||||
|
||||
// POST: api/Assignments
|
||||
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
|
||||
// more details see https://aka.ms/RazorPagesCRUD.
|
||||
[HttpPost]
|
||||
public async Task<ActionResult<Assignment>> PostAssignment(Assignment assignment)
|
||||
{
|
||||
_context.Assignments.Add(assignment);
|
||||
try
|
||||
{
|
||||
await _context.SaveChangesAsync();
|
||||
}
|
||||
catch (DbUpdateException)
|
||||
{
|
||||
if (AssignmentExists(assignment.ProjectId))
|
||||
{
|
||||
return Conflict();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
return CreatedAtAction("GetAssignment", new { id = assignment.ProjectId }, assignment);
|
||||
}
|
||||
|
||||
// DELETE: api/Assignments/5
|
||||
[HttpDelete("{id}")]
|
||||
public async Task<ActionResult<Assignment>> DeleteAssignment(int id)
|
||||
{
|
||||
var assignment = await _context.Assignments.FindAsync(id);
|
||||
if (assignment == null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
_context.Assignments.Remove(assignment);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
return assignment;
|
||||
}
|
||||
|
||||
private bool AssignmentExists(int id)
|
||||
{
|
||||
return _context.Assignments.Any(e => e.ProjectId == id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -94,6 +94,40 @@ namespace TicketManager.Controllers
|
|||
return CreatedAtAction("GetProject", new { id = project.Id }, project);
|
||||
}
|
||||
|
||||
[HttpPost("{id}/addmembers")]
|
||||
public async Task<ActionResult<Project>> PostAssignment(int id, List<User> usersToAdd)
|
||||
{
|
||||
var project = await _context.Projects.FindAsync(id);
|
||||
|
||||
if (project == null)
|
||||
{ return NotFound(); }
|
||||
|
||||
List<Assignment> assignments = project.AddMembers(usersToAdd);
|
||||
|
||||
foreach (var assignment in assignments)
|
||||
{ _context.Assignments.Add(assignment); }
|
||||
|
||||
await _context.SaveChangesAsync();
|
||||
// try
|
||||
// {
|
||||
// await _context.SaveChangesAsync();
|
||||
// }
|
||||
// catch (DbUpdateException)
|
||||
// {
|
||||
// if (AssignmentExists(assignment.ProjectId))
|
||||
// {
|
||||
// return Conflict();
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// throw;
|
||||
// }
|
||||
// }
|
||||
|
||||
// return CreatedAtAction("GetAssignment", new { id = assignment.ProjectId }, assignment);
|
||||
return project;
|
||||
}
|
||||
|
||||
// DELETE: api/Projects/5
|
||||
[HttpDelete("{id}")]
|
||||
public async Task<ActionResult<Project>> DeleteProject(int id)
|
||||
|
|
@ -114,5 +148,9 @@ namespace TicketManager.Controllers
|
|||
{
|
||||
return _context.Projects.Any(e => e.Id == id);
|
||||
}
|
||||
private bool AssignmentExists(int id)
|
||||
{
|
||||
return _context.Assignments.Any(e => e.ProjectId == id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ namespace TicketManager.Models
|
|||
{
|
||||
return this.Assignments.Select(a => a.User).ToList();
|
||||
}
|
||||
public void AddMembers(List<User> usersToAdd)
|
||||
public List<Assignment> AddMembers(List<User> usersToAdd)
|
||||
{
|
||||
foreach (var user in usersToAdd)
|
||||
{
|
||||
|
|
@ -73,6 +73,7 @@ namespace TicketManager.Models
|
|||
};
|
||||
this.Assignments.Add(newAssign);
|
||||
}
|
||||
return this.Assignments;
|
||||
}
|
||||
public void RemoveMembers(List<User> membersToRemove)
|
||||
{
|
||||
|
|
|
|||
729
client/package-lock.json
generated
729
client/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -10,8 +10,11 @@
|
|||
"@types/node": "^12.12.26",
|
||||
"@types/react": "^16.9.19",
|
||||
"@types/react-dom": "^16.9.5",
|
||||
"@types/react-router-dom": "^5.1.3",
|
||||
"history": "^4.10.1",
|
||||
"react": "^16.12.0",
|
||||
"react-dom": "^16.12.0",
|
||||
"react-router-dom": "^5.1.2",
|
||||
"react-scripts": "3.3.1",
|
||||
"typescript": "^3.7.5"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
import React, { FC } from "react";
|
||||
import { Button } from "./Button";
|
||||
import { FloatingButton } from "./FloatingButton";
|
||||
|
||||
type AvatarListProps = {
|
||||
avatars: string[];
|
||||
|
|
@ -10,6 +12,7 @@ export const AvatarList: FC<AvatarListProps> = ({ avatars }) => {
|
|||
{avatars.map((avatar: string) => (
|
||||
<img className="circle" src={avatar} width="50vh" height="50vh" />
|
||||
))}
|
||||
<FloatingButton icon="add" color="grey" size="small" />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
25
client/src/components/Button.tsx
Normal file
25
client/src/components/Button.tsx
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
import React, { FC, Children } from "react";
|
||||
|
||||
interface IProps {
|
||||
icon?: string;
|
||||
size?: string;
|
||||
shape?: string;
|
||||
color?: string;
|
||||
text?: string;
|
||||
}
|
||||
|
||||
export const Button: FC<IProps> = ({
|
||||
size = "small",
|
||||
shape = "",
|
||||
color,
|
||||
text,
|
||||
children
|
||||
}) => {
|
||||
return (
|
||||
<button
|
||||
className={`waves-effect waves-light btn-${size} ${shape} ${color}`}
|
||||
>
|
||||
{children}
|
||||
</button>
|
||||
);
|
||||
};
|
||||
21
client/src/components/FloatingButton.tsx
Normal file
21
client/src/components/FloatingButton.tsx
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
import React, { FC } from "react";
|
||||
import { Button } from "./Button";
|
||||
|
||||
interface IProps {
|
||||
icon?: string;
|
||||
size?: string;
|
||||
color?: string;
|
||||
}
|
||||
|
||||
export const FloatingButton: FC<IProps> = ({
|
||||
icon = "add",
|
||||
size = "small",
|
||||
color = "red"
|
||||
}) => {
|
||||
const iconComponent = <i className="material-icons left">{icon}</i>;
|
||||
return (
|
||||
<Button color={color} size={size} shape="btn-floating">
|
||||
{iconComponent}
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
|
@ -5,10 +5,7 @@ type HeaderProps = {
|
|||
description: string;
|
||||
};
|
||||
|
||||
export const Header: FC<HeaderProps> = ({
|
||||
title,
|
||||
description
|
||||
}) => {
|
||||
export const Header: FC<HeaderProps> = ({ title, description }) => {
|
||||
return (
|
||||
<>
|
||||
<h2>{title}</h2>
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ export const TicketList: FC<TicketListProps> = ({ tickets }) => {
|
|||
return (
|
||||
<div className="row">
|
||||
{tickets.map((t: Ticket) => (
|
||||
<li key={t.Id}>{t.Title}</li>
|
||||
<li key={t.id}>{t.title}</li>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -4,25 +4,48 @@ import { ProjectPage } from "../pages/ProjectPage";
|
|||
import ProjectVM from "../viewModels/ProjectVM";
|
||||
import { Constants } from "../utils/Constants";
|
||||
import { Project } from "../types/Project";
|
||||
import { Ticket } from "../types/Ticket";
|
||||
import { User } from "../types/User";
|
||||
|
||||
export const ProjectController: FC = () => {
|
||||
const [project, setProject] = useState({});
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const { id } = useParams();
|
||||
// const [project, setProject] = useState({} as Project);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
// const { id } = useParams();
|
||||
|
||||
const getProject: Function = (id: number) => {
|
||||
fetch(`${Constants.getProjectURI}/${id}`)
|
||||
.then(res => res.json())
|
||||
.catch(err => console.log(err))
|
||||
.then(data => setProject(data))
|
||||
.finally(() => setIsLoading(false));
|
||||
// const getProject: Function = (id: number) => {
|
||||
// fetch(`${Constants.getProjectURI}/${id}`)
|
||||
// .then(res => res.json())
|
||||
// .catch(err => console.log(err))
|
||||
// .then(data => setProject(data))
|
||||
// .finally(() => setIsLoading(false));
|
||||
// };
|
||||
|
||||
// useEffect(() => {
|
||||
// getProject(id);
|
||||
// }, []);
|
||||
|
||||
// const viewModel = new ProjectVM(project);
|
||||
// console.log(viewModel.getMembers());
|
||||
|
||||
const tickets: Ticket[] = [
|
||||
{
|
||||
id: 1,
|
||||
title: "Ticket #1"
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: "Ticket #2"
|
||||
}
|
||||
];
|
||||
|
||||
const project: Project = {
|
||||
id: 1,
|
||||
title: "Project Title",
|
||||
description: "What is it about",
|
||||
progression: 25,
|
||||
tickets: tickets
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
getProject(id);
|
||||
}, []);
|
||||
|
||||
const viewModel = new ProjectVM(project as Project);
|
||||
const viewModel = new ProjectVM(project);
|
||||
|
||||
return isLoading ? <p>Loading ...</p> : <ProjectPage viewModel={viewModel} />;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,5 +1,9 @@
|
|||
import React from "react";
|
||||
|
||||
export const HomePage: React.FC = () => {
|
||||
return <div className="App"></div>;
|
||||
return (
|
||||
<div className="App">
|
||||
<p>HomePage</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -9,18 +9,12 @@ interface IProps {
|
|||
viewModel: ProjectVM;
|
||||
}
|
||||
export const ProjectPage: FC<IProps> = ({ viewModel }) => {
|
||||
const {
|
||||
title,
|
||||
description,
|
||||
// avatars,
|
||||
value,
|
||||
tickets
|
||||
} = viewModel;
|
||||
const { title, description, avatars, value, tickets } = viewModel;
|
||||
return (
|
||||
<div className="section">
|
||||
<div className="container">
|
||||
<Header title={title} description={description} />
|
||||
{/* <AvatarList avatars={avatars} /> */}
|
||||
<AvatarList avatars={avatars} />
|
||||
<ProgressBar value={value} />
|
||||
{/* <TabView> */}
|
||||
<TicketList tickets={tickets} />
|
||||
|
|
|
|||
|
|
@ -7,6 +7,5 @@ export interface Project {
|
|||
description: string;
|
||||
progression: number;
|
||||
tickets: Ticket[];
|
||||
|
||||
getUsers(): User[];
|
||||
// getMembers(): User[];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
export interface Ticket {
|
||||
Id: number;
|
||||
Title: string;
|
||||
id: number;
|
||||
title: string;
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue