UI project page

This commit is contained in:
Ruidy Nemausat 2020-02-08 15:08:40 +01:00
parent 9e47a6e1d8
commit 4710f0a551
16 changed files with 811 additions and 243 deletions

View 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);
}
}
}

View file

@ -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);
}
}
}

View file

@ -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

File diff suppressed because it is too large Load diff

View file

@ -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"
},

View file

@ -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>
);
};

View 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>
);
};

View 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>
);
};

View file

@ -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>

View file

@ -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>
);

View file

@ -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} />;
};

View file

@ -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>
);
};

View file

@ -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} />

View file

@ -7,6 +7,5 @@ export interface Project {
description: string;
progression: number;
tickets: Ticket[];
getUsers(): User[];
// getMembers(): User[];
}

View file

@ -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