From 6ca9e1efb21cb823ac59bc09ce20e61d84216747 Mon Sep 17 00:00:00 2001 From: Ruidy Nemausat Date: Fri, 14 Feb 2020 17:17:51 +0100 Subject: [PATCH 01/21] - --- Properties/launchSettings.json | 60 +++++++++++++++++----------------- TicketManager.csproj | 12 +++---- 2 files changed, 36 insertions(+), 36 deletions(-) diff --git a/Properties/launchSettings.json b/Properties/launchSettings.json index d81c005..42e74be 100644 --- a/Properties/launchSettings.json +++ b/Properties/launchSettings.json @@ -1,30 +1,30 @@ -{ - "$schema": "http://json.schemastore.org/launchsettings.json", - "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, - "iisExpress": { - "applicationUrl": "http://localhost:15556", - "sslPort": 44341 - } - }, - "profiles": { - "IIS Express": { - "commandName": "IISExpress", - "launchBrowser": true, - "launchUrl": "weatherforecast", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - }, - "TicketManager": { - "commandName": "Project", - "launchBrowser": true, - "launchUrl": "weatherforecast", - "applicationUrl": "https://localhost:5001;http://localhost:5000", - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - } - } -} +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:15556", + "sslPort": 44341 + } + }, + "profiles": { + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "weatherforecast", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "TicketManager": { + "commandName": "Project", + "launchBrowser": true, + "launchUrl": "weatherforecast", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "https://localhost:5001;http://localhost:5000" + } + } +} \ No newline at end of file diff --git a/TicketManager.csproj b/TicketManager.csproj index 79dbdef..a122478 100644 --- a/TicketManager.csproj +++ b/TicketManager.csproj @@ -17,16 +17,16 @@ - - - + + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + - - + + From beeee5b3baad1d616d6cb079a1f8d94bc6a2d01f Mon Sep 17 00:00:00 2001 From: Ruidy Nemausat Date: Mon, 17 Feb 2020 21:52:11 +0100 Subject: [PATCH 02/21] uow proj part1 --- Controllers/ProjectsController.cs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/Controllers/ProjectsController.cs b/Controllers/ProjectsController.cs index d6d8ee6..d2bff55 100644 --- a/Controllers/ProjectsController.cs +++ b/Controllers/ProjectsController.cs @@ -17,12 +17,7 @@ namespace TicketManager.Controllers [ApiController] public class ProjectsController : ControllerBase { - private readonly IProjectRepository _projectRepo; - - public ProjectsController(IProjectRepository projectRepo) - { - _projectRepo = projectRepo; - } + private UnitOfWork _context; /// /// Returns all existing projects. @@ -38,7 +33,7 @@ namespace TicketManager.Controllers [ProducesResponseType(StatusCodes.Status200OK)] public async Task> GetProjects() { - return await _projectRepo.List(); + return await _context.Projects.List(); } /// @@ -57,7 +52,7 @@ namespace TicketManager.Controllers [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task> GetProject(int id) { - Project project = await _projectRepo.Get(id); + Project project = await _context.Projects.Get(id); if (project == null) { return NotFound(); } return project; } From c3d1218f3cb6839b3ae6b94e03d89293dc90a4c5 Mon Sep 17 00:00:00 2001 From: Ruidy Nemausat Date: Mon, 17 Feb 2020 23:46:04 +0100 Subject: [PATCH 03/21] uow proj done --- Controllers/ProjectsController.cs | 348 +++++++++++++++--------------- 1 file changed, 171 insertions(+), 177 deletions(-) diff --git a/Controllers/ProjectsController.cs b/Controllers/ProjectsController.cs index d2bff55..8091d06 100644 --- a/Controllers/ProjectsController.cs +++ b/Controllers/ProjectsController.cs @@ -1,7 +1,4 @@ -using System; using System.Collections.Generic; -using System.Linq; -using System.Net.Mime; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; @@ -9,7 +6,6 @@ using Microsoft.EntityFrameworkCore; using TicketManager.Data; using TicketManager.Models; - namespace TicketManager.Controllers { [Produces("application/json")] @@ -17,210 +13,212 @@ namespace TicketManager.Controllers [ApiController] public class ProjectsController : ControllerBase { - private UnitOfWork _context; + private AppDbContext _dbContext; + public ProjectsController(AppDbContext context) + { + _dbContext = context; + } /// - /// Returns all existing projects. + /// Returns all projects stored in the database. /// /// /// Sample request: /// - /// GET: api/Projects + /// GET: api/v1/Projects /// /// - /// Returns all existing projects + /// Returns a list of projects [HttpGet] [ProducesResponseType(StatusCodes.Status200OK)] public async Task> GetProjects() { + UnitOfWork _context = new UnitOfWork(_dbContext); return await _context.Projects.List(); } /// - /// Returns a specific project. + /// Locate a specific project stored in the database by its Id /// /// /// Sample request: /// - /// GET: api/Projects/2 + /// GET: api/v1/Projects/2 /// /// - /// Returns a specific project + /// Returns a project object /// If the required project is null [HttpGet("{id}")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task> GetProject(int id) { + UnitOfWork _context = new UnitOfWork(_dbContext); Project project = await _context.Projects.Get(id); if (project == null) { return NotFound(); } return project; } - // /// - // /// Updates a specific project. - // /// - // /// - // /// Sample request: - // /// - // /// PUT: api/Projects/3 - // /// { - // /// "id": "357727fd-5262-4522-b8a3-38271d43de84", - // /// "firstName": "Thomas", - // /// "lastName": "Price", - // /// "presentation": "New Team?!", - // /// "email": "tp@mail.com", - // /// "phone": "0198237645" - // /// } - // /// - // /// - // /// Returns the modified project - // /// Request was succesful but no content is changed - // /// If the required project is null - // [HttpPut("{id}")] - // [ProducesResponseType(StatusCodes.Status200OK)] - // [ProducesResponseType(StatusCodes.Status204NoContent)] - // [ProducesResponseType(StatusCodes.Status404NotFound)] - // public async Task PutProject(int id, Project project) - // { - // if (id != project.Id) { return BadRequest(); } + /// + /// Updates the specific project with Id. + /// + /// + /// Sample request: + /// + /// PUT: api/v1/Projects/3 + /// { + /// "id": "357727fd-5262-4522-b8a3-38271d43de84", + /// "firstName": "Thomas", + /// "lastName": "Price", + /// "presentation": "New Team?!", + /// "email": "tp@mail.com", + /// "phone": "0198237645" + /// } + /// + /// + /// Request was succesful but no content is changed + /// If the required project is null + [HttpPut("{id}")] + [ProducesResponseType(StatusCodes.Status204NoContent)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task PutProject(int id, Project project) + { + UnitOfWork _context = new UnitOfWork(_dbContext); + if (id != project.Id) { return BadRequest(); } + try + { + _context.Projects.Update(project); + await _context.Complete(); + } + catch (DbUpdateConcurrencyException) + { + if (!_context.Projects.Exists(id)) { return NotFound(); } + else { throw; } + } + return NoContent(); + } - // try - // { - // await _projectRepo.Update(project); - // } - // catch (DbUpdateConcurrencyException) - // { - // if (!_projectRepo.Exists(id)) - // { - // return NotFound(); - // } - // else - // { - // throw; - // } - // } + /// + /// Creates a project. + /// + /// + /// Sample request: + /// + /// POST: api/v1/Projects/ + /// { + /// "firstName": "Thomas", + /// "lastName": "Price", + /// "presentation": "New Team?!", + /// "email": "tp@mail.com", + /// "phone": "0198237645" + /// } + /// + /// + /// Returns the created project + [HttpPost] + [ProducesResponseType(StatusCodes.Status201Created)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task> PostProject(Project project) + { + UnitOfWork _context = new UnitOfWork(_dbContext); + if (!ModelState.IsValid) { return BadRequest(); } + _context.Projects.Add(project); + await _context.Complete(); + return CreatedAtAction("GetProject", new { id = project.Id }, project); + } - // return NoContent(); - // } + /// + /// Deletes the project identified by its Id + /// + /// + /// Sample request: + /// + /// DELETE: api/v1/Projects/5 + /// + /// + /// Returns the deleted project + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + [HttpDelete("{id}")] + public async Task DeleteProject(int id) + { + UnitOfWork _context = new UnitOfWork(_dbContext); + var project = await _context.Projects.Get(id); + if (project == null) + { + return NotFound(); + } + _context.Projects.Delete(project); + await _context.Complete(); + return Ok(); + } - // /// - // /// Creates a project. - // /// - // /// - // /// Sample request: - // /// - // /// POST: api/Projects/ - // /// { - // /// "firstName": "Thomas", - // /// "lastName": "Price", - // /// "presentation": "New Team?!", - // /// "email": "tp@mail.com", - // /// "phone": "0198237645" - // /// } - // /// - // /// - // /// Returns the created project - // [HttpPost] - // [ProducesResponseType(StatusCodes.Status201Created)] - // [ProducesResponseType(StatusCodes.Status404NotFound)] - // public async Task> PostProject(Project project) - // { - // if (!ModelState.IsValid) { return BadRequest(); } - // await _projectRepo.AddAsync(project); + /// + /// Gets a project members. + /// + /// + /// Sample request: + /// + /// GET: api/v1/Projects/5/Members + /// + /// + /// Returns the project members as a list of users. + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + [HttpGet("{id}/members")] + public async Task>> GetProjectMembers(int id) + { + UnitOfWork _context = new UnitOfWork(_dbContext); + Project project = await _context.Projects.Get(id); + if (project == null) + { return NotFound(); } + return project.GetMembers(); + } - // return CreatedAtAction("GetProject", new { id = project.Id }, project); - // } - - - - - // /// - // /// Deletes a project. - // /// - // /// - // /// Sample request: - // /// - // /// DELETE: api/Projects/5 - // /// - // /// - // /// Returns the deleted project - // [ProducesResponseType(StatusCodes.Status200OK)] - // [ProducesResponseType(StatusCodes.Status404NotFound)] - // [HttpDelete("{id}")] - // public async Task> DeleteProject(int id) - // { - // var project = await _projectRepo.GetByIdAsync(id); - // if (project == null) - // { - // return NotFound(); - // } - // await _projectRepo.DeleteAsync(id); - // return project; - // } - - // /// - // /// Gets a project members. - // /// - // /// - // /// Sample request: - // /// - // /// GET: api/Projects/5/Members - // /// - // /// - // /// Returns the project members - // [ProducesResponseType(StatusCodes.Status200OK)] - // [ProducesResponseType(StatusCodes.Status404NotFound)] - // [HttpGet("{id}/members")] - // public async Task>> GetProjectMembers(int id) - // { - // Project project = await _projectRepo.GetByIdAsync(id); - // if (project == null) - // { return NotFound(); } - // return project.GetMembers(); - // } - - // /// - // /// Updates a project members. - // /// - // /// - // /// Sample request: - // /// - // /// PUT: api/Projects/5/Members - // /// { - // /// "id": "357727fd-5262-4522-b8a3-38271d43de84", - // /// "firstName": "Thomas", - // /// "lastName": "Price", - // /// "presentation": "New Team?!", - // /// "email": "tp@mail.com", - // /// "phone": "0198237645" - // /// } - // /// - // /// No content - // [ProducesResponseType(StatusCodes.Status204NoContent)] - // [ProducesResponseType(StatusCodes.Status404NotFound)] - // [HttpPut("{id}/members")] - // public async Task> SetProjectMembers(int id, List projectMembers) - // { - // Project project = await _projectRepo.GetByIdAsync(id); - // if (project == null) - // { - // return NotFound(); - // } - // project.SetMembers(projectMembers); - // try - // { - // await _projectRepo.UpdateAsync(project); - // } - // catch (DbUpdateException /* ex */) - // { - // //Log the error (uncomment ex variable name and write a log.) - // ModelState.AddModelError("", "Unable to save changes. " + - // "Try again, and if the problem persists, " + - // "see your system administrator."); - // } - // return NoContent(); - // } + /// + /// Updates a project members. + /// + /// + /// Sample request: + /// + /// PUT: api/v1/Projects/5/Members + /// { + /// "id": "357727fd-5262-4522-b8a3-38271d43de84", + /// "firstName": "Thomas", + /// "lastName": "Price", + /// "presentation": "New Team?!", + /// "email": "tp@mail.com", + /// "phone": "0198237645" + /// } + /// + /// No content + /// Not Found + [ProducesResponseType(StatusCodes.Status204NoContent)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + [HttpPut("{id}/members")] + public async Task> SetProjectMembers(int id, List projectMembers) + { + UnitOfWork _context = new UnitOfWork(_dbContext); + Project project = await _context.Projects.Get(id); + if (project == null) + { + return NotFound(); + } + project.SetMembers(projectMembers); + try + { + _context.Projects.Update(project); + await _context.Complete(); + } + catch (DbUpdateException /* ex */) + { + //Log the error (uncomment ex variable name and write a log.) + ModelState.AddModelError("", "Unable to save changes. " + + "Try again, and if the problem persists, " + + "see your system administrator."); + } + return NoContent(); + } // // /// // // /// Assign a user to a project. @@ -228,7 +226,7 @@ namespace TicketManager.Controllers // // /// // // /// Sample request: // // /// - // // /// POST: api/Projects/addmembers + // // /// POST: api/v1/Projects/addmembers // // /// [{ // // /// "id": "357727fd-5262-4522-b8a3-38271d43de84", // // /// "firstName": "Thomas", @@ -271,7 +269,7 @@ namespace TicketManager.Controllers // // /// // // /// Sample request: // // /// - // // /// PUT: api/Projects/removemembers + // // /// PUT: api/v1/Projects/removemembers // // /// [{ // // /// "id": "357727fd-5262-4522-b8a3-38271d43de84", // // /// "firstName": "Thomas", @@ -303,9 +301,5 @@ namespace TicketManager.Controllers // // } // // return NoContent(); // // } - - - - } } From d5d5d5886603b4c5d767e1c729aca8bee9387d4f Mon Sep 17 00:00:00 2001 From: Ruidy Nemausat Date: Tue, 18 Feb 2020 08:37:43 +0100 Subject: [PATCH 04/21] Unit of Work removed. Save done in the Repositories. Proj, Tickets & AppUsers Repo done. --- Controllers/AppUsersController.cs | 63 +---- Controllers/ProjectsController.cs | 37 +-- Controllers/ProjectsController_working.cs | 317 ---------------------- Controllers/TicketsController.cs | 69 +---- Data/AppUserRepository.cs | 38 +++ Data/GenericRepository.cs | 9 +- Data/Interfaces/IAppUserRepository.cs | 12 + Data/Interfaces/IGenericRepository.cs | 6 +- Data/Interfaces/ITicketRepository.cs | 11 + Data/Interfaces/IUnitOfWork.cs | 2 + Data/ProjectRepository.cs | 4 +- Data/TicketRepository.cs | 40 +++ Data/UnitOfWork.cs | 6 + 13 files changed, 163 insertions(+), 451 deletions(-) delete mode 100644 Controllers/ProjectsController_working.cs create mode 100644 Data/AppUserRepository.cs create mode 100644 Data/Interfaces/IAppUserRepository.cs create mode 100644 Data/Interfaces/ITicketRepository.cs create mode 100644 Data/TicketRepository.cs diff --git a/Controllers/AppUsersController.cs b/Controllers/AppUsersController.cs index d6bbc2b..42c9104 100644 --- a/Controllers/AppUsersController.cs +++ b/Controllers/AppUsersController.cs @@ -14,31 +14,29 @@ namespace TicketManager.Controllers [ApiController] public class UsersController : ControllerBase { - private readonly AppDbContext _context; + private readonly IAppUserRepository _users; - public UsersController(AppDbContext context) + public UsersController(IAppUserRepository users) { - _context = context; + _users = users; } // GET: api/Users [HttpGet] - public async Task>> GetUsers() + public async Task> GetUsers() { - return await getAllAppUsersAsync(); + return await _users.List(); } // GET: api/Users/5 [HttpGet("{id}")] public async Task> GetUser(Guid id) { - var user = await getAppUserByIdAsync(id); - + var user = await _users.GetUser(id); if (user == null) { return NotFound(); } - return user; } @@ -52,16 +50,13 @@ namespace TicketManager.Controllers { return BadRequest(); } - - _context.Entry(user).State = EntityState.Modified; - try { - await _context.SaveChangesAsync(); + await _users.Update(user); } catch (DbUpdateConcurrencyException) { - if (!UserExists(id)) + if (!_users.Exists(id)) { return NotFound(); } @@ -70,7 +65,6 @@ namespace TicketManager.Controllers throw; } } - return NoContent(); } @@ -80,32 +74,27 @@ namespace TicketManager.Controllers [HttpPost] public async Task> PostUser(AppUser user) { - _context.AppUsers.Add(user); - await _context.SaveChangesAsync(); - + await _users.Add(user); return CreatedAtAction("GetUser", new { id = user.Id }, user); } // DELETE: api/Users/5 [HttpDelete("{id}")] - public async Task> DeleteUser(int id) + public async Task> DeleteUser(Guid id) { - var user = await _context.AppUsers.FindAsync(id); + var user = await _users.GetUser(id); if (user == null) { return NotFound(); } - - _context.AppUsers.Remove(user); - await _context.SaveChangesAsync(); - + await _users.Delete(user); return user; } [HttpGet("{id}/projects")] public async Task>> GetAppUserProjects(Guid id) { - AppUser user = await getAppUserByIdAsync(id); + AppUser user = await _users.GetUser(id); if (user == null) { return BadRequest(); @@ -116,36 +105,12 @@ namespace TicketManager.Controllers [HttpGet("{id}/tickets/")] public async Task>> GetAppUserTickets(Guid id) { - AppUser user = await getAppUserByIdAsync(id); + AppUser user = await _users.GetUser(id); if (user == null) { return BadRequest(); } return user.GetTickets(); } - - private bool UserExists(Guid id) - { - return _context.AppUsers.Any(e => e.Id == id); - } - - private IQueryable appUserQuery() - { - return _context.AppUsers - .Include(p => p.Assignments) - .ThenInclude(a => a.Project) - .ThenInclude(p => p.Tickets) - .Include(p => p.Edits); - } - - private async Task>> getAllAppUsersAsync() - { - return await appUserQuery().ToListAsync(); - } - - private async Task getAppUserByIdAsync(Guid id) - { - return await appUserQuery().FirstOrDefaultAsync(a => a.Id == id); - } } } diff --git a/Controllers/ProjectsController.cs b/Controllers/ProjectsController.cs index 8091d06..18c6de9 100644 --- a/Controllers/ProjectsController.cs +++ b/Controllers/ProjectsController.cs @@ -13,10 +13,10 @@ namespace TicketManager.Controllers [ApiController] public class ProjectsController : ControllerBase { - private AppDbContext _dbContext; - public ProjectsController(AppDbContext context) + private IProjectRepository _projects; + public ProjectsController(IProjectRepository context) { - _dbContext = context; + _projects = context; } /// @@ -33,8 +33,7 @@ namespace TicketManager.Controllers [ProducesResponseType(StatusCodes.Status200OK)] public async Task> GetProjects() { - UnitOfWork _context = new UnitOfWork(_dbContext); - return await _context.Projects.List(); + return await _projects.List(); } /// @@ -53,8 +52,7 @@ namespace TicketManager.Controllers [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task> GetProject(int id) { - UnitOfWork _context = new UnitOfWork(_dbContext); - Project project = await _context.Projects.Get(id); + Project project = await _projects.Get(id); if (project == null) { return NotFound(); } return project; } @@ -83,16 +81,14 @@ namespace TicketManager.Controllers [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task PutProject(int id, Project project) { - UnitOfWork _context = new UnitOfWork(_dbContext); if (id != project.Id) { return BadRequest(); } try { - _context.Projects.Update(project); - await _context.Complete(); + await _projects.Update(project); } catch (DbUpdateConcurrencyException) { - if (!_context.Projects.Exists(id)) { return NotFound(); } + if (!_projects.Exists(id)) { return NotFound(); } else { throw; } } return NoContent(); @@ -120,10 +116,8 @@ namespace TicketManager.Controllers [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task> PostProject(Project project) { - UnitOfWork _context = new UnitOfWork(_dbContext); if (!ModelState.IsValid) { return BadRequest(); } - _context.Projects.Add(project); - await _context.Complete(); + await _projects.Add(project); return CreatedAtAction("GetProject", new { id = project.Id }, project); } @@ -142,14 +136,12 @@ namespace TicketManager.Controllers [HttpDelete("{id}")] public async Task DeleteProject(int id) { - UnitOfWork _context = new UnitOfWork(_dbContext); - var project = await _context.Projects.Get(id); + var project = await _projects.Get(id); if (project == null) { return NotFound(); } - _context.Projects.Delete(project); - await _context.Complete(); + await _projects.Delete(project); return Ok(); } @@ -168,8 +160,7 @@ namespace TicketManager.Controllers [HttpGet("{id}/members")] public async Task>> GetProjectMembers(int id) { - UnitOfWork _context = new UnitOfWork(_dbContext); - Project project = await _context.Projects.Get(id); + var project = await _projects.Get(id); if (project == null) { return NotFound(); } return project.GetMembers(); @@ -198,8 +189,7 @@ namespace TicketManager.Controllers [HttpPut("{id}/members")] public async Task> SetProjectMembers(int id, List projectMembers) { - UnitOfWork _context = new UnitOfWork(_dbContext); - Project project = await _context.Projects.Get(id); + Project project = await _projects.Get(id); if (project == null) { return NotFound(); @@ -207,8 +197,7 @@ namespace TicketManager.Controllers project.SetMembers(projectMembers); try { - _context.Projects.Update(project); - await _context.Complete(); + await _projects.Update(project); } catch (DbUpdateException /* ex */) { diff --git a/Controllers/ProjectsController_working.cs b/Controllers/ProjectsController_working.cs deleted file mode 100644 index 3936677..0000000 --- a/Controllers/ProjectsController_working.cs +++ /dev/null @@ -1,317 +0,0 @@ -// using System; -// using System.Collections.Generic; -// using System.Linq; -// using System.Net.Mime; -// using System.Threading.Tasks; -// using Microsoft.AspNetCore.Http; -// using Microsoft.AspNetCore.Mvc; -// using Microsoft.EntityFrameworkCore; -// using TicketManager.Data; -// using TicketManager.Models; - - -// namespace TicketManager.Controllers -// { -// [Produces("application/json")] -// [Route("api/v1/[controller]")] -// [ApiController] -// public class ProjectsController : ControllerBase -// { -// private readonly IProjectRepository _projectRepo; - -// public ProjectsController(IProjectRepository projectRepo) -// { -// _projectRepo = projectRepo; -// } - -// /// -// /// Returns all existing projects. -// /// -// /// -// /// Sample request: -// /// -// /// GET: api/Projects -// /// -// /// -// /// Returns all existing projects -// [HttpGet] -// [ProducesResponseType(StatusCodes.Status200OK)] -// public async Task> GetProjects() -// { -// return await _projectRepo.ListAsync(); -// // GetAllProjectsAsync(); -// } - -// /// -// /// Returns a specific project. -// /// -// /// -// /// Sample request: -// /// -// /// GET: api/Projects/2 -// /// -// /// -// /// Returns a specific project -// /// If the required project is null -// [HttpGet("{id}")] -// [ProducesResponseType(StatusCodes.Status200OK)] -// [ProducesResponseType(StatusCodes.Status404NotFound)] -// public async Task> GetProject(int id) -// { -// Project project = await _projectRepo.GetByIdAsync(id); -// if (project == null) { return NotFound(); } -// return project; -// } - -// /// -// /// Updates a specific project. -// /// -// /// -// /// Sample request: -// /// -// /// PUT: api/Projects/3 -// /// { -// /// "id": "357727fd-5262-4522-b8a3-38271d43de84", -// /// "firstName": "Thomas", -// /// "lastName": "Price", -// /// "presentation": "New Team?!", -// /// "email": "tp@mail.com", -// /// "phone": "0198237645" -// /// } -// /// -// /// -// /// Returns the modified project -// /// Request was succesful but no content is changed -// /// If the required project is null -// [HttpPut("{id}")] -// [ProducesResponseType(StatusCodes.Status200OK)] -// [ProducesResponseType(StatusCodes.Status204NoContent)] -// [ProducesResponseType(StatusCodes.Status404NotFound)] -// public async Task PutProject(int id, Project project) -// { -// if (id != project.Id) { return BadRequest(); } - -// try -// { -// await _projectRepo.UpdateAsync(project); -// } -// catch (DbUpdateConcurrencyException) -// { -// if (!_projectRepo.Exists(id)) -// { -// return NotFound(); -// } -// else -// { -// throw; -// } -// } - -// return NoContent(); -// } - -// /// -// /// Creates a project. -// /// -// /// -// /// Sample request: -// /// -// /// POST: api/Projects/ -// /// { -// /// "firstName": "Thomas", -// /// "lastName": "Price", -// /// "presentation": "New Team?!", -// /// "email": "tp@mail.com", -// /// "phone": "0198237645" -// /// } -// /// -// /// -// /// Returns the created project -// [HttpPost] -// [ProducesResponseType(StatusCodes.Status201Created)] -// [ProducesResponseType(StatusCodes.Status404NotFound)] -// public async Task> PostProject(Project project) -// { -// if (!ModelState.IsValid) { return BadRequest(); } -// await _projectRepo.AddAsync(project); - -// return CreatedAtAction("GetProject", new { id = project.Id }, project); -// } - - - - -// /// -// /// Deletes a project. -// /// -// /// -// /// Sample request: -// /// -// /// DELETE: api/Projects/5 -// /// -// /// -// /// Returns the deleted project -// [ProducesResponseType(StatusCodes.Status200OK)] -// [ProducesResponseType(StatusCodes.Status404NotFound)] -// [HttpDelete("{id}")] -// public async Task> DeleteProject(int id) -// { -// var project = await _projectRepo.GetByIdAsync(id); -// if (project == null) -// { -// return NotFound(); -// } -// await _projectRepo.DeleteAsync(id); -// return project; -// } - -// /// -// /// Gets a project members. -// /// -// /// -// /// Sample request: -// /// -// /// GET: api/Projects/5/Members -// /// -// /// -// /// Returns the project members -// [ProducesResponseType(StatusCodes.Status200OK)] -// [ProducesResponseType(StatusCodes.Status404NotFound)] -// [HttpGet("{id}/members")] -// public async Task>> GetProjectMembers(int id) -// { -// Project project = await _projectRepo.GetByIdAsync(id); -// if (project == null) -// { return NotFound(); } -// return project.GetMembers(); -// } - -// /// -// /// Updates a project members. -// /// -// /// -// /// Sample request: -// /// -// /// PUT: api/Projects/5/Members -// /// { -// /// "id": "357727fd-5262-4522-b8a3-38271d43de84", -// /// "firstName": "Thomas", -// /// "lastName": "Price", -// /// "presentation": "New Team?!", -// /// "email": "tp@mail.com", -// /// "phone": "0198237645" -// /// } -// /// -// /// No content -// [ProducesResponseType(StatusCodes.Status204NoContent)] -// [ProducesResponseType(StatusCodes.Status404NotFound)] -// [HttpPut("{id}/members")] -// public async Task> SetProjectMembers(int id, List projectMembers) -// { -// Project project = await _projectRepo.GetByIdAsync(id); -// if (project == null) -// { -// return NotFound(); -// } -// project.SetMembers(projectMembers); -// try -// { -// await _projectRepo.UpdateAsync(project); -// } -// catch (DbUpdateException /* ex */) -// { -// //Log the error (uncomment ex variable name and write a log.) -// ModelState.AddModelError("", "Unable to save changes. " + -// "Try again, and if the problem persists, " + -// "see your system administrator."); -// } -// return NoContent(); -// } - -// // /// -// // /// Assign a user to a project. -// // /// -// // /// -// // /// Sample request: -// // /// -// // /// POST: api/Projects/addmembers -// // /// [{ -// // /// "id": "357727fd-5262-4522-b8a3-38271d43de84", -// // /// "firstName": "Thomas", -// // /// "lastName": "Price", -// // /// "presentation": "New Team?!", -// // /// "email": "tp@mail.com", -// // /// "phone": "0198237645" -// // /// }] -// // /// -// // /// -// // /// Returns the created project -// // [ProducesResponseType(StatusCodes.Status204NoContent)] -// // [ProducesResponseType(StatusCodes.Status404NotFound)] -// // [HttpPut("{id}/addMembers")] -// // public async Task> AddMembersToProject(int id, List usersToAdd) -// // { -// // if (usersToAdd == null) -// // { -// // return BadRequest(); -// // } -// // Project project = await GetProjectByIdAsync(id); -// // project.AddMembers(usersToAdd); -// // try -// // { -// // await _context.SaveChangesAsync(); -// // } -// // catch (DbUpdateException /* ex */) -// // { -// // //Log the error (uncomment ex variable name and write a log.) -// // ModelState.AddModelError("", "Unable to save changes. " + -// // "Try again, and if the problem persists, " + -// // "see your system administrator."); -// // } -// // return NoContent(); -// // } - -// // /// -// // /// Remove a user to a project. -// // /// -// // /// -// // /// Sample request: -// // /// -// // /// PUT: api/Projects/removemembers -// // /// [{ -// // /// "id": "357727fd-5262-4522-b8a3-38271d43de84", -// // /// "firstName": "Thomas", -// // /// "lastName": "Price", -// // /// "presentation": "New Team?!", -// // /// "email": "tp@mail.com", -// // /// "phone": "0198237645" -// // /// }] -// // /// -// // /// -// // /// Returns the created project -// // [ProducesResponseType(StatusCodes.Status204NoContent)] -// // [ProducesResponseType(StatusCodes.Status404NotFound)] -// // [HttpPut("{id}/removeMembers")] -// // public async Task> RemoveMembersFromProject(int id, List usersToRemove) -// // { -// // Project project = await GetProjectByIdAsync(id); -// // project.RemoveMembers(usersToRemove); -// // try -// // { -// // await _context.SaveChangesAsync(); -// // } -// // catch (DbUpdateException /* ex */) -// // { -// // //Log the error (uncomment ex variable name and write a log.) -// // ModelState.AddModelError("", "Unable to save changes. " + -// // "Try again, and if the problem persists, " + -// // "see your system administrator."); -// // } -// // return NoContent(); -// // } - - - - -// } -// } diff --git a/Controllers/TicketsController.cs b/Controllers/TicketsController.cs index 17dac2c..5c9cd37 100644 --- a/Controllers/TicketsController.cs +++ b/Controllers/TicketsController.cs @@ -14,31 +14,29 @@ namespace TicketManager.Controllers [ApiController] public class TicketsController : ControllerBase { - private readonly AppDbContext _context; + private readonly ITicketRepository _tickets; - public TicketsController(AppDbContext context) + public TicketsController(ITicketRepository tickets) { - _context = context; + _tickets = tickets; } // GET: api/Tickets [HttpGet] - public async Task>> GetTickets() + public async Task> GetTickets() { - return await getAllTicketsAsync(); + return await _tickets.List(); } // GET: api/Tickets/5 [HttpGet("{id}")] public async Task> GetTicket(int id) { - var ticket = await getTicketByIdAsync(id); - + var ticket = await _tickets.Get(id); if (ticket == null) { return NotFound(); } - return ticket; } @@ -52,16 +50,13 @@ namespace TicketManager.Controllers { return BadRequest(); } - - _context.Entry(ticket).State = EntityState.Modified; - try { - await _context.SaveChangesAsync(); + await _tickets.Update(ticket); } catch (DbUpdateConcurrencyException) { - if (!TicketExists(id)) + if (!_tickets.Exists(id)) { return NotFound(); } @@ -70,7 +65,6 @@ namespace TicketManager.Controllers throw; } } - return NoContent(); } @@ -80,9 +74,7 @@ namespace TicketManager.Controllers [HttpPost] public async Task> PostTicket(Ticket ticket) { - _context.Tickets.Add(ticket); - await _context.SaveChangesAsync(); - + await _tickets.Add(ticket); return CreatedAtAction("GetTicket", new { id = ticket.Id }, ticket); } @@ -90,59 +82,28 @@ namespace TicketManager.Controllers [HttpDelete("{id}")] public async Task> DeleteTicket(int id) { - var ticket = await _context.Tickets.FindAsync(id); + var ticket = await _tickets.Get(id); if (ticket == null) { return NotFound(); } - - _context.Tickets.Remove(ticket); - await _context.SaveChangesAsync(); - + await _tickets.Delete(ticket); return ticket; } [HttpGet("{id}/assignees")] public async Task>> GetTicketAssignees(int id) { - Ticket ticket = await getTicketByIdAsync(id); + Ticket ticket = await _tickets.Get(id); return ticket.GetAssignees(); } [HttpPut("{id}/closed")] - public async Task CloseTicket(int id) + public async Task CloseTicket(int id) { - Ticket ticket = await getTicketByIdAsync(id); + Ticket ticket = await _tickets.Get(id); ticket.Close(); - return NoContent(); - } - - private bool TicketExists(int id) - { - return _context.Tickets.Any(e => e.Id == id); - } - - private IQueryable ticketQuery() // problem with link - { - return _context.Tickets - .Include(p => p.Project) - .ThenInclude(a => a.Assignments) - .ThenInclude(p => p.User) - // .Include(p => p.Edits) - // .Include(p => p.Notes) - // .Include(p => p.Files) - // .Include(p => p.Creator) - ; - } - - private async Task>> getAllTicketsAsync() - { - return await ticketQuery().ToListAsync(); - } - - private async Task getTicketByIdAsync(int id) - { - return await ticketQuery().FirstOrDefaultAsync(a => a.Id == id); + return await PutTicket(ticket.Id, ticket); } } } diff --git a/Data/AppUserRepository.cs b/Data/AppUserRepository.cs new file mode 100644 index 0000000..a281ec8 --- /dev/null +++ b/Data/AppUserRepository.cs @@ -0,0 +1,38 @@ +using System.Threading.Tasks; +using TicketManager.Models; +using System.Linq; +using System; +using Microsoft.EntityFrameworkCore; +using System.Collections.Generic; + +namespace TicketManager.Data +{ + public class AppUserRepository : GenericRepository, IAppUserRepository + { + private readonly IQueryable _query; + public AppUserRepository(AppDbContext context) : base(context) + { + _query = _dbSet + .Include(p => p.Assignments) + .ThenInclude(a => a.Project) + .ThenInclude(p => p.Tickets) + .Include(p => p.Edits) + .AsNoTracking(); + } + + public async Task GetUser(Guid id) + { + return await _query.FirstOrDefaultAsync(p => p.Id == id); + } + + public override async Task> List() + { + return await _query.ToListAsync(); + } + + public bool Exists(Guid id) + { + return _dbSet.Any(e => e.Id == id); + } + } +} \ No newline at end of file diff --git a/Data/GenericRepository.cs b/Data/GenericRepository.cs index ac7d4e8..1a90aa1 100644 --- a/Data/GenericRepository.cs +++ b/Data/GenericRepository.cs @@ -17,16 +17,18 @@ namespace TicketManager.Data _dbSet = _context.Set(); } - public void Add(T entity) + public async Task Add(T entity) { _dbSet.Add(entity); + return await _context.SaveChangesAsync(); } - public void Delete(T entity) + public async Task Delete(T entity) { if (_context.Entry(entity).State == EntityState.Detached) { _dbSet.Attach(entity); } _dbSet.Remove(entity); + return await _context.SaveChangesAsync(); } public async Task> Find(int id, Expression> expr) @@ -43,10 +45,11 @@ namespace TicketManager.Data return await _dbSet.AsNoTracking().ToListAsync(); } - public void Update(T entity) + public async Task Update(T entity) { _dbSet.Attach(entity); _context.Entry(entity).State = EntityState.Modified; + return await _context.SaveChangesAsync(); } } } \ No newline at end of file diff --git a/Data/Interfaces/IAppUserRepository.cs b/Data/Interfaces/IAppUserRepository.cs new file mode 100644 index 0000000..ab57db3 --- /dev/null +++ b/Data/Interfaces/IAppUserRepository.cs @@ -0,0 +1,12 @@ +using System; +using System.Threading.Tasks; +using TicketManager.Models; + +namespace TicketManager.Data +{ + public interface IAppUserRepository : IGenericRepository + { + Task GetUser(Guid id); + bool Exists(Guid id); + } +} \ No newline at end of file diff --git a/Data/Interfaces/IGenericRepository.cs b/Data/Interfaces/IGenericRepository.cs index e8594d8..915ef12 100644 --- a/Data/Interfaces/IGenericRepository.cs +++ b/Data/Interfaces/IGenericRepository.cs @@ -11,10 +11,10 @@ namespace TicketManager.Data Task Get(int id); Task> Find(int id, Expression> expr); - void Add(T entity); + Task Add(T entity); - void Update(T entity); + Task Update(T entity); - void Delete(T entity); + Task Delete(T entity); } } \ No newline at end of file diff --git a/Data/Interfaces/ITicketRepository.cs b/Data/Interfaces/ITicketRepository.cs new file mode 100644 index 0000000..de8af26 --- /dev/null +++ b/Data/Interfaces/ITicketRepository.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using TicketManager.Models; + +namespace TicketManager.Data +{ + public interface ITicketRepository : IGenericRepository + { + bool Exists(int id); + } +} \ No newline at end of file diff --git a/Data/Interfaces/IUnitOfWork.cs b/Data/Interfaces/IUnitOfWork.cs index 6a614f3..eab4e21 100644 --- a/Data/Interfaces/IUnitOfWork.cs +++ b/Data/Interfaces/IUnitOfWork.cs @@ -6,6 +6,8 @@ namespace TicketManager.Data public interface IUnitOfWork : IDisposable { IProjectRepository Projects { get; } + IAppUserRepository AppUsers { get; } + ITicketRepository Tickets { get; } Task Complete(); } } \ No newline at end of file diff --git a/Data/ProjectRepository.cs b/Data/ProjectRepository.cs index 7349bfd..675fe9c 100644 --- a/Data/ProjectRepository.cs +++ b/Data/ProjectRepository.cs @@ -30,7 +30,9 @@ namespace TicketManager.Data } public bool Exists(int id) - { return _dbSet.Any(e => e.Id == id); } + { + return _dbSet.Any(e => e.Id == id); + } public async Task> GetMembers(int id) { diff --git a/Data/TicketRepository.cs b/Data/TicketRepository.cs new file mode 100644 index 0000000..272adda --- /dev/null +++ b/Data/TicketRepository.cs @@ -0,0 +1,40 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using System.Linq; +using TicketManager.Models; +using Microsoft.EntityFrameworkCore; + +namespace TicketManager.Data +{ + public class TicketRepository : GenericRepository, ITicketRepository + { + private IQueryable _query; + public TicketRepository(AppDbContext context) : base(context) + { + _query = _dbSet + .Include(p => p.Project) + .ThenInclude(a => a.Assignments) + .ThenInclude(p => p.User) + // .Include(p => p.Edits) + // .Include(p => p.Notes) + // .Include(p => p.Files) + // .Include(p => p.Creator) + .AsNoTracking(); + } + + public override async Task Get(int id) + { + return await _query.FirstOrDefaultAsync(p => p.Id == id); + } + + public override async Task> List() + { + return await _query.ToListAsync(); + } + + public bool Exists(int id) + { + return _dbSet.Any(e => e.Id == id); + } + } +} \ No newline at end of file diff --git a/Data/UnitOfWork.cs b/Data/UnitOfWork.cs index ad82b8b..3a70423 100644 --- a/Data/UnitOfWork.cs +++ b/Data/UnitOfWork.cs @@ -10,10 +10,16 @@ namespace TicketManager.Data { _context = context; Projects = new ProjectRepository(_context); + Tickets = new TicketRepository(_context); + AppUsers = new AppUserRepository(_context); } public IProjectRepository Projects { get; private set; } + public IAppUserRepository AppUsers { get; private set; } + + public ITicketRepository Tickets { get; private set; } + public async Task Complete() { return await _context.SaveChangesAsync(); From e59676d04a0242030c440509895a46d30649e3d2 Mon Sep 17 00:00:00 2001 From: Ruidy Nemausat Date: Tue, 18 Feb 2020 08:52:31 +0100 Subject: [PATCH 05/21] Unit of Work removed. Save done in the Repositories. Proj, Tickets & AppUsers Repo done. --- Data/AppUserRepository.cs | 3 +-- Data/ProjectRepository.cs | 3 +-- Data/TicketRepository.cs | 2 +- Startup.cs | 2 ++ 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Data/AppUserRepository.cs b/Data/AppUserRepository.cs index a281ec8..66a2cde 100644 --- a/Data/AppUserRepository.cs +++ b/Data/AppUserRepository.cs @@ -16,8 +16,7 @@ namespace TicketManager.Data .Include(p => p.Assignments) .ThenInclude(a => a.Project) .ThenInclude(p => p.Tickets) - .Include(p => p.Edits) - .AsNoTracking(); + .Include(p => p.Edits); } public async Task GetUser(Guid id) diff --git a/Data/ProjectRepository.cs b/Data/ProjectRepository.cs index 675fe9c..ec8dede 100644 --- a/Data/ProjectRepository.cs +++ b/Data/ProjectRepository.cs @@ -15,8 +15,7 @@ namespace TicketManager.Data .Include(p => p.Assignments).ThenInclude(a => a.User) .Include(p => p.Tickets) .Include(p => p.Manager) - .Include(p => p.Files) - .AsNoTracking(); + .Include(p => p.Files); } public override async Task Get(int id) diff --git a/Data/TicketRepository.cs b/Data/TicketRepository.cs index 272adda..e142c8f 100644 --- a/Data/TicketRepository.cs +++ b/Data/TicketRepository.cs @@ -19,7 +19,7 @@ namespace TicketManager.Data // .Include(p => p.Notes) // .Include(p => p.Files) // .Include(p => p.Creator) - .AsNoTracking(); + ; } public override async Task Get(int id) diff --git a/Startup.cs b/Startup.cs index 9c41d9c..3da6027 100644 --- a/Startup.cs +++ b/Startup.cs @@ -38,6 +38,8 @@ namespace TicketManager services.AddDbContext(options => options.UseSqlite(Configuration.GetConnectionString("Sqlite"))); services.AddScoped(); + services.AddScoped(); + services.AddScoped(); services.AddControllers() .AddNewtonsoftJson(options => { From 83dcab1c15424e7a35f0f79fa737f08cc02d13a3 Mon Sep 17 00:00:00 2001 From: Ruidy Nemausat Date: Wed, 19 Feb 2020 22:47:41 +0100 Subject: [PATCH 06/21] Set API authentication using Auth0. API endpoints require Authorized JWT --- Controllers/AppUsersController.cs | 4 +-- Controllers/AssignmentsController.cs | 4 +-- Controllers/FilesController.cs | 4 +-- Controllers/HistoriesController.cs | 4 +-- Controllers/NotesController.cs | 4 +-- Controllers/ProjectsController.cs | 3 ++ Controllers/TicketsController.cs | 5 ++-- README.md | 4 +-- Scripts/cleanDevDb.sh | 5 ---- Scripts/scaffoldControllers.sh | 6 ---- Startup.cs | 41 ++++++++++++++-------------- TicketManager.csproj | 3 ++ appsettings.json | 4 +++ client/src/react-app-env.d.ts | 1 - 14 files changed, 44 insertions(+), 48 deletions(-) delete mode 100755 Scripts/cleanDevDb.sh delete mode 100755 Scripts/scaffoldControllers.sh delete mode 100644 client/src/react-app-env.d.ts diff --git a/Controllers/AppUsersController.cs b/Controllers/AppUsersController.cs index 42c9104..34a1f72 100644 --- a/Controllers/AppUsersController.cs +++ b/Controllers/AppUsersController.cs @@ -1,15 +1,15 @@ 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; +using Microsoft.AspNetCore.Authorization; namespace TicketManager.Controllers { + [Authorize] [Route("api/v1/[controller]")] [ApiController] public class UsersController : ControllerBase diff --git a/Controllers/AssignmentsController.cs b/Controllers/AssignmentsController.cs index 400f0a7..67f39e1 100644 --- a/Controllers/AssignmentsController.cs +++ b/Controllers/AssignmentsController.cs @@ -1,8 +1,7 @@ -using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using TicketManager.Data; @@ -10,6 +9,7 @@ using TicketManager.Models; namespace TicketManager.Controllers { + [Authorize] [Route("api/[controller]")] [ApiController] public class AssignmentsController : ControllerBase diff --git a/Controllers/FilesController.cs b/Controllers/FilesController.cs index 6481b76..3b422d8 100644 --- a/Controllers/FilesController.cs +++ b/Controllers/FilesController.cs @@ -1,8 +1,7 @@ -using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using TicketManager.Data; @@ -10,6 +9,7 @@ using TicketManager.Models; namespace TicketManager.Controllers { + [Authorize] [Route("api/v1/[controller]")] [ApiController] public class FilesController : ControllerBase diff --git a/Controllers/HistoriesController.cs b/Controllers/HistoriesController.cs index 0934909..67eee4a 100644 --- a/Controllers/HistoriesController.cs +++ b/Controllers/HistoriesController.cs @@ -1,8 +1,7 @@ -using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using TicketManager.Data; @@ -10,6 +9,7 @@ using TicketManager.Models; namespace TicketManager.Controllers { + [Authorize] [Route("api/v1/[controller]")] [ApiController] public class HistoriesController : ControllerBase diff --git a/Controllers/NotesController.cs b/Controllers/NotesController.cs index f2a537b..20fe5dc 100644 --- a/Controllers/NotesController.cs +++ b/Controllers/NotesController.cs @@ -1,8 +1,7 @@ -using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using TicketManager.Data; @@ -10,6 +9,7 @@ using TicketManager.Models; namespace TicketManager.Controllers { + [Authorize] [Route("api/v1/[controller]")] [ApiController] public class NotesController : ControllerBase diff --git a/Controllers/ProjectsController.cs b/Controllers/ProjectsController.cs index 18c6de9..1167f67 100644 --- a/Controllers/ProjectsController.cs +++ b/Controllers/ProjectsController.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; @@ -8,6 +9,8 @@ using TicketManager.Models; namespace TicketManager.Controllers { + // [Authorize(Roles = "Admin")] + [Authorize] [Produces("application/json")] [Route("api/v1/[controller]")] [ApiController] diff --git a/Controllers/TicketsController.cs b/Controllers/TicketsController.cs index 5c9cd37..90844f0 100644 --- a/Controllers/TicketsController.cs +++ b/Controllers/TicketsController.cs @@ -1,8 +1,6 @@ -using System; using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using TicketManager.Data; @@ -10,6 +8,7 @@ using TicketManager.Models; namespace TicketManager.Controllers { + [Authorize] [Route("api/v1/[controller]")] [ApiController] public class TicketsController : ControllerBase diff --git a/README.md b/README.md index d37ede2..e28c7ca 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,5 @@ - Ensure Tickets Edits belong to Project Edits - Ensure Tickets Files belong to Project Files - Async model methods ? -- setMembers & removeMembers from project api not working -- Write a query class to refactor code and optimize perf on get queries (AsNoTracking) -- repository + strategy to decouple controllers from DbContext. Easier testing - update assignments automatically from context +- use PATCH instead of PUT diff --git a/Scripts/cleanDevDb.sh b/Scripts/cleanDevDb.sh deleted file mode 100755 index f470323..0000000 --- a/Scripts/cleanDevDb.sh +++ /dev/null @@ -1,5 +0,0 @@ -rm -r Migrations -rm app.db -dotnet ef migrations add Migration1 -dotnet ef database update -dotnet run \ No newline at end of file diff --git a/Scripts/scaffoldControllers.sh b/Scripts/scaffoldControllers.sh deleted file mode 100755 index e68e6a7..0000000 --- a/Scripts/scaffoldControllers.sh +++ /dev/null @@ -1,6 +0,0 @@ -rm Controllers/AppUsersController.cs -rm Controllers/TicketsController.cs -rm Controllers/ProjectsController.cs -dotnet aspnet-codegenerator controller -name AppUsersController -async -api -m AppUser -dc AppDbContext -outDir Controllers -dotnet aspnet-codegenerator controller -name TicketsController -async -api -m Ticket -dc AppDbContext -outDir Controllers -dotnet aspnet-codegenerator controller -name ProjectsController -async -api -m Project -dc AppDbContext -outDir Controllers \ No newline at end of file diff --git a/Startup.cs b/Startup.cs index 3da6027..f86c247 100644 --- a/Startup.cs +++ b/Startup.cs @@ -19,6 +19,7 @@ using TicketManager.Data; using TicketManager.Models; using Microsoft.AspNetCore.Mvc.NewtonsoftJson; using Newtonsoft.Json; +using Microsoft.AspNetCore.Authentication.JwtBearer; [assembly: ApiController] namespace TicketManager @@ -32,7 +33,6 @@ namespace TicketManager public IConfiguration Configuration { get; } - // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddDbContext(options => @@ -40,12 +40,26 @@ namespace TicketManager services.AddScoped(); services.AddScoped(); services.AddScoped(); - services.AddControllers() - .AddNewtonsoftJson(options => + + services.AddAuthentication(options => { - options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; // avoid cycle ref errors + options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; + options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; + }).AddJwtBearer(options => + { + options.Authority = "https://dev-fyjrvohx.auth0.com/"; + options.Audience = "https://localhost:5001/api/V1/"; + //options.Authority = $"https://{Configuration["Auth0:Domain"]}/"; + //options.Audience = Configuration["Auth0:Audience"]; }); + services.AddControllers() + .AddNewtonsoftJson(options => + { + options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; // avoid cycle ref errors + } + ); + services.AddSpaStaticFiles(configuration => { configuration.RootPath = "client/build"; @@ -72,17 +86,12 @@ namespace TicketManager services.AddSwaggerGenNewtonsoftSupport(); // explicit opt-in - needs to be placed after AddSwaggerGen() } - - - // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IServiceProvider serviceProvider) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); - var repository = serviceProvider.GetRequiredService(); - - // InitializeDatabaseAsync(repository).Wait() + // var repository = serviceProvider.GetRequiredService(); } else { @@ -92,7 +101,6 @@ namespace TicketManager app.UseHttpsRedirection(); app.UseDefaultFiles(); - app.UseSwagger(); app.UseSwaggerUI(c => @@ -100,11 +108,9 @@ namespace TicketManager c.SwaggerEndpoint("/swagger/v1/swagger.json", "Ticket Manager API v1"); }); - - app.UseSpaStaticFiles(); app.UseRouting(); - + app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints => @@ -123,9 +129,4 @@ namespace TicketManager }); } } -} - - - - - +} \ No newline at end of file diff --git a/TicketManager.csproj b/TicketManager.csproj index 397adb0..1f38ad6 100644 --- a/TicketManager.csproj +++ b/TicketManager.csproj @@ -16,6 +16,9 @@ + + + diff --git a/appsettings.json b/appsettings.json index 390f10c..070e52f 100644 --- a/appsettings.json +++ b/appsettings.json @@ -10,5 +10,9 @@ "AllowedHosts": "*", "ConnectionStrings": { "Sqlite": "Data Source=app.db" + }, + "Auth0": { + "Domain": "https://dev-fyjrvohx.auth0.com/", + "Audience": "https://localhost:5001/api/V1/" } } \ No newline at end of file diff --git a/client/src/react-app-env.d.ts b/client/src/react-app-env.d.ts deleted file mode 100644 index 6431bc5..0000000 --- a/client/src/react-app-env.d.ts +++ /dev/null @@ -1 +0,0 @@ -/// From 112ccbefeee62030e0b365b826e9b57debb10cd9 Mon Sep 17 00:00:00 2001 From: Ruidy Nemausat Date: Thu, 20 Feb 2020 09:00:34 +0100 Subject: [PATCH 07/21] Light code cleaning --- Data/ProjectRepository working.cs | 57 ------------------------------- Data/UnitOfWork.cs | 1 - Models/AppUser.cs | 3 +- Models/File.cs | 2 -- Models/Project.cs | 3 +- Models/Ticket.cs | 2 +- README.md | 1 + TicketManager.csproj | 7 +--- 8 files changed, 5 insertions(+), 71 deletions(-) delete mode 100644 Data/ProjectRepository working.cs diff --git a/Data/ProjectRepository working.cs b/Data/ProjectRepository working.cs deleted file mode 100644 index c63560c..0000000 --- a/Data/ProjectRepository working.cs +++ /dev/null @@ -1,57 +0,0 @@ -// using System.Threading.Tasks; -// using TicketManager.Models; -// using System.Linq; -// using Microsoft.EntityFrameworkCore; -// using System.Collections.Generic; -// using Microsoft.AspNetCore.Mvc; - -// namespace TicketManager.Data -// { -// public class ProjectRepository : IProjectRepository -// { -// private readonly AppDbContext _context; -// private readonly IQueryable _query; -// public ProjectRepository(AppDbContext context) -// { -// _context = context; -// _query = _context.Projects -// .Include(p => p.Assignments) -// .ThenInclude(a => a.User) -// .Include(p => p.Tickets) -// .Include(p => p.Manager) -// .Include(p => p.Files); -// } - -// public Task AddAsync(Project project) -// { -// _context.Projects.Add(project); -// return _context.SaveChangesAsync(); -// } - -// public async Task DeleteAsync(int id) -// { -// Project project = await GetByIdAsync(id); -// _context.Projects.Remove(project); -// return await _context.SaveChangesAsync(); -// } - -// public async Task GetByIdAsync(int id) -// { -// return await _query.FirstOrDefaultAsync(p => p.Id == id); -// } - -// public async Task> ListAsync() -// { -// return await _query.ToListAsync(); -// } - -// public Task UpdateAsync(Project project) -// { -// _context.Entry(project).State = EntityState.Modified; -// return _context.SaveChangesAsync(); -// } -// public bool Exists(int id) -// { return _context.Projects.Any(e => e.Id == id); } - -// } -// } \ No newline at end of file diff --git a/Data/UnitOfWork.cs b/Data/UnitOfWork.cs index 3a70423..1a0e21a 100644 --- a/Data/UnitOfWork.cs +++ b/Data/UnitOfWork.cs @@ -24,7 +24,6 @@ namespace TicketManager.Data { return await _context.SaveChangesAsync(); } - public void Dispose() { _context.DisposeAsync(); diff --git a/Models/AppUser.cs b/Models/AppUser.cs index 8d81141..63f2a4d 100644 --- a/Models/AppUser.cs +++ b/Models/AppUser.cs @@ -38,7 +38,6 @@ namespace TicketManager.Models // [Display(Name = "Avatar")] // public byte[] Picture { get; set; } - // public Role Role { get; set; } public List Assignments { get; set; } = new List(); @@ -53,7 +52,7 @@ namespace TicketManager.Models public List GetTickets() { - List tickets = new List(); + var tickets = new List(); GetProjects().ForEach(p => tickets.Concat(p.Tickets)); return tickets; } diff --git a/Models/File.cs b/Models/File.cs index 8dd01e4..b2b7485 100644 --- a/Models/File.cs +++ b/Models/File.cs @@ -5,8 +5,6 @@ namespace TicketManager.Models { public class File { - - public int Id { get; set; } public string FileName { get; set; } diff --git a/Models/Project.cs b/Models/Project.cs index acebe5f..372cd35 100644 --- a/Models/Project.cs +++ b/Models/Project.cs @@ -119,8 +119,7 @@ namespace TicketManager.Models this.AddMembers(projectMembers); } } - // public int GetMembersCount() => this.GetMembers().Count(); - // public void GetTicketsCount() => this.Tickets.Count(); + public void GetTicketsUpdates() { throw new NotImplementedException("Not Implemented"); } diff --git a/Models/Ticket.cs b/Models/Ticket.cs index abd1ede..24ec37a 100644 --- a/Models/Ticket.cs +++ b/Models/Ticket.cs @@ -29,7 +29,7 @@ namespace TicketManager.Models public Difficulty Difficulty { get; set; } = Difficulty.Undefined; public Category Category { get; set; } = Category.Undefined; - [Display(Name = "Created By")] + // [Display(Name = "Created By")] // public AppUser Creator { get; set; } public Guid CreatorId { get; set; } diff --git a/README.md b/README.md index e28c7ca..100dedc 100644 --- a/README.md +++ b/README.md @@ -43,3 +43,4 @@ - Async model methods ? - update assignments automatically from context - use PATCH instead of PUT +- logging diff --git a/TicketManager.csproj b/TicketManager.csproj index 1f38ad6..812b03b 100644 --- a/TicketManager.csproj +++ b/TicketManager.csproj @@ -3,10 +3,7 @@ netcoreapp3.1 - - 8.0 - - + 8.0 @@ -16,9 +13,7 @@ - - From b861a658925f9c2aff59c089f1ff307ac1551264 Mon Sep 17 00:00:00 2001 From: Ruidy Nemausat Date: Thu, 20 Feb 2020 10:43:07 +0100 Subject: [PATCH 08/21] project page ticket tab done --- client/src/components/HorizontalCard.tsx | 58 ++++++------- client/src/components/TabRouter.tsx | 22 +---- client/src/components/TabRouterHeader.tsx | 100 +++++++++++----------- client/src/components/TicketList.tsx | 53 ++++-------- client/src/pages/ProjectPage.tsx | 5 +- 5 files changed, 99 insertions(+), 139 deletions(-) diff --git a/client/src/components/HorizontalCard.tsx b/client/src/components/HorizontalCard.tsx index a0d20dd..791222f 100644 --- a/client/src/components/HorizontalCard.tsx +++ b/client/src/components/HorizontalCard.tsx @@ -1,54 +1,44 @@ import React, { FC, MouseEvent } from "react"; import { AvatarList } from "./AvatarList"; +import { Link } from "react-router-dom"; interface IProps { title: string; - tasksTotalCount?: number; - tasksDone?: number; remainingDays?: number; - avatars: string[]; validateTicket: (event: MouseEvent) => void; archiveTicket: (event: MouseEvent) => void; } export const HorizontalCard: FC = ({ title, - tasksDone, - tasksTotalCount, remainingDays, - avatars, archiveTicket, validateTicket }) => { return ( -
-
-
-
-
-
-
{title}
-
- Due {remainingDays} days - {/* */} -
- {/* playlist_add_check - - {" "} - {tasksDone}/{tasksTotalCount} - */} - - - - check - - - - - archive - - -
+
+
+
+
+
+
+ + {title} + +
+
+ Due {remainingDays} days +
diff --git a/client/src/components/TabRouter.tsx b/client/src/components/TabRouter.tsx index 7a5c217..4709463 100644 --- a/client/src/components/TabRouter.tsx +++ b/client/src/components/TabRouter.tsx @@ -6,36 +6,22 @@ import { Switch, Route, useRouteMatch, Redirect } from "react-router-dom"; interface IProps { tickets: Ticket[]; - tasksTotalCount?: number; - tasksDone?: number; remainingDays?: number; - avatars: string[]; + tabNames: string[]; } -export const TabRouter: FC = ({ - tickets, - tasksDone, - tasksTotalCount, - remainingDays, - avatars -}) => { +export const TabRouter: FC = ({ tickets, remainingDays, tabNames }) => { const { url } = useRouteMatch(); return ( <>
- + - + diff --git a/client/src/components/TabRouterHeader.tsx b/client/src/components/TabRouterHeader.tsx index b21eb11..ed4ce15 100644 --- a/client/src/components/TabRouterHeader.tsx +++ b/client/src/components/TabRouterHeader.tsx @@ -1,12 +1,51 @@ import React, { FC, useState } from "react"; import { Link, useRouteMatch } from "react-router-dom"; +interface IProps { + tabClass?: string; + nTabs: number; + tabNames: string[]; +} + +export const TabRouterHeader: FC = ({ + tabClass = "tab col s4", + nTabs, + tabNames +}) => { + const [isActive, setIsActive] = useState(0); + + return ( + <> +
    + {tabNames.map((name, i) => ( + + ))} +
  • +
+ + ); +}; + interface TabUnitProps { tabClass: string; isActive: number; setIsActive: React.Dispatch>; text: string; value: string; + nTabs: number; } const TabUnit: FC = ({ @@ -14,15 +53,23 @@ const TabUnit: FC = ({ isActive, setIsActive, text, - value + value, + nTabs }) => { const { url } = useRouteMatch(); return ( -
  • +
  • setIsActive(parseInt(value))} > {text} @@ -30,50 +77,3 @@ const TabUnit: FC = ({
  • ); }; - -interface IProps { - tabClass?: string; -} - -export const TabRouterHeader: FC = ({ - tabClass = "tab col s3", - - children -}) => { - const [isActive, setIsActive] = useState(1); - - // const switchTab = (e: React.MouseEvent): void => { - // e.preventDefault(); - // setIsActive(e.target.id); - // }; - - return ( - <> -
    -
      - - - -
    -
    - - ); -}; diff --git a/client/src/components/TicketList.tsx b/client/src/components/TicketList.tsx index b7835a0..df56bb0 100644 --- a/client/src/components/TicketList.tsx +++ b/client/src/components/TicketList.tsx @@ -5,48 +5,33 @@ import { HorizontalCard } from "./HorizontalCard"; type TicketListProps = { tickets: Ticket[]; - tasksTotalCount?: number; - tasksDone?: number; remainingDays?: number; - avatars: string[]; }; -export const TicketList: FC = ({ - tickets, - tasksDone, - tasksTotalCount, - remainingDays, - avatars -}) => { +export const TicketList: FC = ({ tickets, remainingDays }) => { const archiveTicket = () => {}; const validateTicket = () => {}; return ( -
    + <>
    -
    -

    Tickets

    -
    -
    - -
    +

    Tickets

    +
    - -
      - {tickets.map((t: Ticket) => ( -
    • - -
    • - ))} -
    -
    +
    +
      + {tickets.map((t: Ticket) => ( +
    • + +
    • + ))} +
    +
    + ); }; diff --git a/client/src/pages/ProjectPage.tsx b/client/src/pages/ProjectPage.tsx index 5ce7d1e..95d484b 100644 --- a/client/src/pages/ProjectPage.tsx +++ b/client/src/pages/ProjectPage.tsx @@ -20,6 +20,7 @@ export const ProjectPage: FC = ({ viewModel }) => { ticketsTotalCount, remainingDays } = viewModel; + const tabNames: string[] = ["Tickets", "Files", "Activity"]; return (
    @@ -35,11 +36,9 @@ export const ProjectPage: FC = ({ viewModel }) => { remainingDays={remainingDays} />
    From 0990e59d64e380e1f70805fce91acc9343688ef6 Mon Sep 17 00:00:00 2001 From: Ruidy Nemausat Date: Thu, 20 Feb 2020 14:16:02 +0100 Subject: [PATCH 09/21] Static Project page done. Activity & Files tabs added. Preloader added. Changed History to Activity --- README.md | 1 + client/src/components/ActivityCollection.tsx | 35 +++++++++++ client/src/components/ActivityList.tsx | 20 +++++++ client/src/components/AppFileList.tsx | 22 +++++++ client/src/components/DropZone.tsx | 7 +++ client/src/components/FileCollection.tsx | 38 ++++++++++++ client/src/components/Preloader.tsx | 55 +++++++++++++++++ client/src/components/TabRouter.tsx | 18 +++++- client/src/components/TabRouterHeader.tsx | 2 +- client/src/controllers/ProjectController.tsx | 63 ++++++++++++++++++-- client/src/pages/ProjectPage.tsx | 6 +- client/src/types/Activity.ts | 10 ++++ client/src/types/AppFile.ts | 9 +++ client/src/types/File.ts | 3 - client/src/types/History.ts | 3 - client/src/types/Project.ts | 4 ++ client/src/types/User.ts | 1 + client/src/viewModels/ProjectVM.ts | 7 ++- 18 files changed, 288 insertions(+), 16 deletions(-) create mode 100644 client/src/components/ActivityCollection.tsx create mode 100644 client/src/components/ActivityList.tsx create mode 100644 client/src/components/AppFileList.tsx create mode 100644 client/src/components/DropZone.tsx create mode 100644 client/src/components/FileCollection.tsx create mode 100644 client/src/components/Preloader.tsx create mode 100644 client/src/types/Activity.ts create mode 100644 client/src/types/AppFile.ts delete mode 100644 client/src/types/File.ts delete mode 100644 client/src/types/History.ts diff --git a/README.md b/README.md index 100dedc..817f04a 100644 --- a/README.md +++ b/README.md @@ -44,3 +44,4 @@ - update assignments automatically from context - use PATCH instead of PUT - logging +- check useRef, useReducer, dispatch diff --git a/client/src/components/ActivityCollection.tsx b/client/src/components/ActivityCollection.tsx new file mode 100644 index 0000000..e351219 --- /dev/null +++ b/client/src/components/ActivityCollection.tsx @@ -0,0 +1,35 @@ +import React, { FC } from "react"; +import { Activity } from "../types/Activity"; + +type IProps = { + activities: Activity[]; +}; + +export const ActivityCollection: FC = ({ activities }) => { + return ( + <> +
      + {activities.map((f: Activity) => ( + + ))} +
    + + ); +}; + +type IFProps = { + activity: Activity; +}; + +export const ActivityEntry: FC = ({ activity }) => { + return ( +
  • + + {/* folder */} + + {activity.user.firstName} {activity.description} {activity.ticket.title} + +

    {activity.date.toDateString()}

    +
  • + ); +}; diff --git a/client/src/components/ActivityList.tsx b/client/src/components/ActivityList.tsx new file mode 100644 index 0000000..010f727 --- /dev/null +++ b/client/src/components/ActivityList.tsx @@ -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 = ({ activities }) => { + return ( + <> +
    +

    Activity

    + +
    + + + ); +}; diff --git a/client/src/components/AppFileList.tsx b/client/src/components/AppFileList.tsx new file mode 100644 index 0000000..449ec93 --- /dev/null +++ b/client/src/components/AppFileList.tsx @@ -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 = ({ files }) => { + return ( + <> +
    +

    Files

    + +
    + + + + ); +}; diff --git a/client/src/components/DropZone.tsx b/client/src/components/DropZone.tsx new file mode 100644 index 0000000..4ff5146 --- /dev/null +++ b/client/src/components/DropZone.tsx @@ -0,0 +1,7 @@ +import React, { FC } from "react"; + +type IProps = {}; + +export const DropZone: FC = () => { + return
    Drag & Drop your files here.
    ; +}; diff --git a/client/src/components/FileCollection.tsx b/client/src/components/FileCollection.tsx new file mode 100644 index 0000000..158c1cb --- /dev/null +++ b/client/src/components/FileCollection.tsx @@ -0,0 +1,38 @@ +import React, { FC } from "react"; +import { AppFile } from "../types/AppFile"; + +type IProps = { + files: AppFile[]; +}; + +export const FileCollection: FC = ({ files }) => { + return ( + <> +
      + {files.map((f: AppFile) => ( + + ))} +
    + + ); +}; + +type IFProps = { + file: AppFile; +}; + +export const FileEntry: FC = ({ file }) => { + return ( +
  • + {/* */} + folder + {file.name} +

    + {file.size}kb {file.format} +

    + + more_vert + +
  • + ); +}; diff --git a/client/src/components/Preloader.tsx b/client/src/components/Preloader.tsx new file mode 100644 index 0000000..5c77cca --- /dev/null +++ b/client/src/components/Preloader.tsx @@ -0,0 +1,55 @@ +import React, { FC } from "react"; + +export const Preloader: FC = () => { + return ( +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + ); +}; diff --git a/client/src/components/TabRouter.tsx b/client/src/components/TabRouter.tsx index 4709463..6623285 100644 --- a/client/src/components/TabRouter.tsx +++ b/client/src/components/TabRouter.tsx @@ -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 = ({ tickets, remainingDays, tabNames }) => { +export const TabRouter: FC = ({ + tickets, + remainingDays, + tabNames, + files, + activities +}) => { const { url } = useRouteMatch(); return ( <> @@ -25,11 +37,11 @@ export const TabRouter: FC = ({ tickets, remainingDays, tabNames }) => {
    - {/* */} + - {/* */} +
    diff --git a/client/src/components/TabRouterHeader.tsx b/client/src/components/TabRouterHeader.tsx index ed4ce15..0d8eb8f 100644 --- a/client/src/components/TabRouterHeader.tsx +++ b/client/src/components/TabRouterHeader.tsx @@ -12,7 +12,7 @@ export const TabRouterHeader: FC = ({ nTabs, tabNames }) => { - const [isActive, setIsActive] = useState(0); + const [isActive, setIsActive] = useState(0); return ( <> diff --git a/client/src/controllers/ProjectController.tsx b/client/src/controllers/ProjectController.tsx index bc97254..289b5c2 100644 --- a/client/src/controllers/ProjectController.tsx +++ b/client/src/controllers/ProjectController.tsx @@ -6,6 +6,9 @@ import { Constants } from "../utils/Constants"; import { Project } from "../types/Project"; import { Ticket } from "../types/Ticket"; import { User } from "../types/User"; +import { AppFile } from "../types/AppFile"; +import { Activity } from "../types/Activity"; +import { Preloader } from "../components/Preloader"; export const ProjectController: FC = () => { // const [project, setProject] = useState({} as Project); @@ -23,10 +26,9 @@ export const ProjectController: FC = () => { // useEffect(() => { // getProject(id); - // }, []); + // }, [id]); // const viewModel = new ProjectVM(project); - // console.log(viewModel.getMembers()); const tickets: Ticket[] = [ { @@ -44,26 +46,77 @@ export const ProjectController: FC = () => { const users: User[] = [ { id: "1", + firstName: "PacMan", picture: "data:image/jpeg;base64,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" }, { id: "2", + firstName: "Avatar", picture: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAMAAACahl6sAAAAM1BMVEUKME7///+El6bw8vQZPVlHZHpmfpHCy9Ojsbzg5ekpSmTR2N44V29XcYayvsd2i5yTpLFbvRYnAAAJcklEQVR4nO2d17arOgxFs+kkofz/154Qmg0uKsuQccddT/vhnOCJLclFMo+//4gedzcApf9B4srrusk+GsqPpj+ypq7zVE9LAdLWWVU+Hx69y2FMwAMGyfusLHwIpooyw9IAQfK+8naDp3OGHvZ0FMhrfPMgVnVjC2kABOQ1MLvi0DEIFj1ILu0LU2WjNRgtSF3pKb4qqtd9IHmjGlJHlc09IHlGcrQcPeUjTAySAGNSkQlRhCCJMGaUC0HSYUx6SmxFAtJDTdylsr4ApC1TY0yquKbCBkk7qnYVzPHFBHkBojhVJWviwgPJrsP4qBgTgbQXdsesjm4pDJDmIuswVZDdFx0ENTtkihoeqSDXD6tVxOFFBHndMKxWvUnzexpIcx/Gg2goJJDhVo6PCMGRAnKTmZuKm3wcJO/upphUqUHy29yVrRhJDORXOKIkEZDf4YiRhEF+iSNCEgb5KY4wSRDkB/yurUEG8nMcocgYABnvbrVL3nMIP0h/d5udKnwzSC/InfPdkJ6eWb0PJE++dyVVyQP5iQmWW27X5QG5druEKafBu0Hqu9saVOHa8HKC/K6BzHKZiRMEZCDF0Nd1/ZfXI/fcOibHOssFgokg9uFA20BhztHEAZIjIohrD/o1wljeFBDEwBo8YUt5Ir/rNLjOIACPFdy/AbEcPdcJBOCxytjeYAM4Kzp6rhOIPhRGNzwmFP3rOoTFI0irtnQKx6fj1Zt+h9njEUS9mKJxfFRrX5lt7wcQtaWTOfTHeIXVJQcQrRW+OYex2j0a66XZINoO8a7fPH2iHF2mC7ZBtB3Czb5QvjizSx7A3308mRzqAwujSywQbYfwc0iU8zqjS0yQ6ztEHX9332KCaGNIYB/Qq1z3yN0oDZBWyeFYJBCkm2sXLhDtpKFwNDMu5TnrZpYGiHbK4Nlwikg5DrYV1g6iPoJmzE5MKd/fOp53EPUaQZaLqH3u+vo2ELWp3wSyWuYGoj9EEIJoV3L9AUS/ZLsJpLNBXmqOu0CW6P5A/dx9IL0FAji/FYKot9EqE0Tvs6QBUe/2CxMEkZAlBNGPhdoAQWyTSmbxUwvUygwQyMmniAPgLt87CODXHuftWJIQgzrfQDC5AfwSgz9MmmG/gWCOqDgZ4JsQeTvZBoJJDhAFEsSDyxUEEUUekk0UEMhjBcEcGsoWVpBU3NcCgkkPkJWrKbdRZvULCMTWhYEdMrayBQRyqHcnSLmAIH7LcWJ8Hch7BsHEdWFpJsZjziCgFBpZ9TPm4e0XBJTTJKt9xjy8RoLI4gimPLP5goCSgWTrEcyzsy8IqmZVMo0H5bJiQToBCOjZ5RcElhjLN3dU7uQMAvoxwQkJZKI1CQzCthJYEigahHuDDi4rFwzCPQ7F1fiDQZgTR5iJwEGYRgIsiECD8BwwMAEfDcIaW8CRBQdhjS1kJQEchDEFhiRKr4KDFPS9FGQNVwEHoW83QjsEHdkfnuIOl6C1NjMItiaCaCWgbdpFJXQ9soh2uoB9aJcCxFdgZwlcrTmvENGlrITBBdpK25Qhd1F2RScq8CKu/gsCL8qN5THjy+Rr5E6joYgPxpdl518QrCf8Kpgjn6C8HLkbb+vt7ZM8wdVvy258khsRfHaS5DalDnlidZT7Erk+SXV5Bj1D3LS29XyhVJuoKHs9Q8S6reK11oUc7vPcr9uswP3SLiDINefXOF5rwCuGzVT6zVkVPfh2wWmHcz4wAwba2cgN1/Tsvleu7//i69CgVyt1GwjOs2+XK3rtbl151Tg3vOeioG40Mz2V+6pQ4xbJHOZj6g0EMxk93tV7fuedvVZpQSPhbwNBGInrymGrwNh1GXmL8F+lAaJ+NU/fzcmvJqvKj7177+1v1GY/GiBKI1Fdy/2XK6upXwaIJpI8B/399W0mH9zzafKaeCF9J0WF+jyCuFusTGzZKhFH8dVLZql2brxgcdVBKb7KG/7UZTmB3XJ6uL/QYT5ScRI74FcHEJ7feopyfGkaeaGlPoCw/BbjZmSBWIvINQNmTxdjWJqwUI8sztR4nYPuIPSTSUnOCZOE3ierqRoJfNSQxDjLEYs8i91eqgFCDSWiFHiuqAN9CwEGCPEISVjvwhS7Mfx6dtX8kC5aqvneGBOEFN2v6RBiYwr3DQOkLhEW6fHFbIwFQnkLiWYmZxE220z/aedPx99C+hiyKR4OzNFhg8S75CJTnxQ1dyugHTLaY10iu9dBpmhQtMz1ABLrkgtHVnRsPUO3OcU25i8cWdGxZbflCBKJqBdMs3aF/dYhNexU9RFcYEmLXYQKghyWdufyldBSU3KpjkKhZclxTXQGCTkL/HZDUIH5+Gkt4SgoCtj7pSYSNJLTK3VVRnmXZxebSMBIzmHABeIdXBebiN9eHYtUZ62ab3BdGkUm+SKJw1bdRXeewaX7qqdAnljg2sVxg3guAk3baofcg9yZ2eZpnHNvSFrEqhB9YPjesmt0pt6Xc8hl7W5L9Q4Xx09ctsrd5VhWeF6nF8SRrZdw49qns//0xTK/AZ8vGr3caTliuzeFNeCJTgafpKlhHd2WP1sy1LqDF798gjKJPLqDr9keoTd43+NyNzC1CI8Xy2lcPtOaVBI5IiAWyQ3e125AcKoXs2Djhy5eVc3KiBxREIPkhjBiLhIjU++4T91IbggjRiCJLSEIwWGddkEaxlVN5KCArPHk8mXVpHk8FHH7JL3n5dPA7C90q7XkeFJucacNmGXeRfswLE71HA79efaGiCN/Ofjmfmtcp8X10tIsqCacV5xfRWjNUiXGYbovWgyFYHcQLak15K9oM5zqmgaeKsHJetbSHfSPzXOiw/rxE9YH4CXaUpsZ0ztemFurP95Jpyvrd29YTpIZr7cEJHqfc7Wl0PFm2+yJR70udaokKFtGPTdm8WdQe24+HmVLlueboWQquBcYYVH2vEzfh8kCks1p90eWsLCyZ8qK7E86Oe+3XYFnBuiWdth20UqZR5SvMoyPg3WNauJipi0LMTQgVq5xUUlZcrPsopPHJ926z8pm7xyFLrH/PxpHSoXKdWgXsLn1scZn1ZDd/2vszN3lt254qkE+qu3yoqLM+ghN3Qz2qcVzUC/ZMFsK/alU6l0OWV/bQz6v6yYbyuN5BaZ4A7Y30vs/PPksS2+qzlvfF7OQmzzcL7W+xa7OIfRuVdtn/tdvdFLnL4OTKcm2W16PmWc4FWWXNSlWM2n3D+uPxuyrcfo74aP+Ac30a82+oLmfAAAAAElFTkSuQmCC" }, { id: "3", + firstName: "Zoey", picture: "data:image/jpeg;base64,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" }, { id: "4", + firstName: "Kory", picture: "data:image/jpeg;base64,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" } ]; + const files: AppFile[] = [ + { + id: 1, + name: "SRS", + description: "App blueprint", + size: 15, + format: "pdf" + }, + { + id: 2, + name: "Business Model Canvas", + description: "Path to 1B$", + size: 2100, + format: "pdf" + } + ]; + + const activities: Activity[] = [ + { + id: 1, + description: " completed the task ", + date: new Date(), + user: users[0], + ticket: tickets[0] + }, + { + id: 3, + description: " added the task ", + date: new Date(), + user: users[1], + ticket: tickets[1] + }, + { + id: 3, + description: " rescheduled the task ", + date: new Date(), + user: users[2], + ticket: tickets[1] + }, + { + id: 4, + description: " added the task ", + date: new Date(), + user: users[3], + ticket: tickets[0] + } + ]; const project: Project = { id: 1, title: "Project Title", @@ -71,10 +124,12 @@ export const ProjectController: FC = () => { progression: 25, tickets: tickets, users: users, - plannedEnding: "2020-02-17 15:51:02.787373" + plannedEnding: "2020-02-17 15:51:02.787373", + files: files, + activities: activities }; const viewModel = new ProjectVM(project); - return isLoading ?

    Loading ...

    : ; + return isLoading ? : ; }; diff --git a/client/src/pages/ProjectPage.tsx b/client/src/pages/ProjectPage.tsx index 95d484b..f98d781 100644 --- a/client/src/pages/ProjectPage.tsx +++ b/client/src/pages/ProjectPage.tsx @@ -18,7 +18,9 @@ export const ProjectPage: FC = ({ viewModel }) => { tickets, ticketsDone, ticketsTotalCount, - remainingDays + remainingDays, + files, + activities } = viewModel; const tabNames: string[] = ["Tickets", "Files", "Activity"]; return ( @@ -38,7 +40,9 @@ export const ProjectPage: FC = ({ viewModel }) => {
    diff --git a/client/src/types/Activity.ts b/client/src/types/Activity.ts new file mode 100644 index 0000000..4fb8157 --- /dev/null +++ b/client/src/types/Activity.ts @@ -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; +} diff --git a/client/src/types/AppFile.ts b/client/src/types/AppFile.ts new file mode 100644 index 0000000..6fc9cec --- /dev/null +++ b/client/src/types/AppFile.ts @@ -0,0 +1,9 @@ +import { User } from "./User"; + +export interface AppFile { + id: number; + name: string; + description: string; + format: string; + size: number; +} diff --git a/client/src/types/File.ts b/client/src/types/File.ts deleted file mode 100644 index f916c15..0000000 --- a/client/src/types/File.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface File { - Id: number; -} diff --git a/client/src/types/History.ts b/client/src/types/History.ts deleted file mode 100644 index 9f3fbf3..0000000 --- a/client/src/types/History.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface History { - Id: number; -} diff --git a/client/src/types/Project.ts b/client/src/types/Project.ts index 9b41fcc..bf3a70f 100644 --- a/client/src/types/Project.ts +++ b/client/src/types/Project.ts @@ -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[]; } diff --git a/client/src/types/User.ts b/client/src/types/User.ts index b31c2e3..88deb83 100644 --- a/client/src/types/User.ts +++ b/client/src/types/User.ts @@ -1,4 +1,5 @@ export interface User { id: string; picture: string; + firstName: string; } diff --git a/client/src/viewModels/ProjectVM.ts b/client/src/viewModels/ProjectVM.ts index 7dd2cf2..490a10a 100644 --- a/client/src/viewModels/ProjectVM.ts +++ b/client/src/viewModels/ProjectVM.ts @@ -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; } } From 14e47378dd9c2089f82f1e2ddb8b755e4494c48b Mon Sep 17 00:00:00 2001 From: Ruidy Nemausat Date: Thu, 20 Feb 2020 14:51:03 +0100 Subject: [PATCH 10/21] Code cleaning --- client/src/App.css | 42 -------------------- client/src/App.tsx | 2 - client/src/components/ActivityCollection.tsx | 10 +++-- client/src/components/AvatarList.tsx | 17 +++++--- client/src/components/Button.tsx | 2 +- client/src/components/FileCollection.tsx | 6 +-- client/src/components/HorizontalCard.tsx | 9 ++--- client/src/components/ProgressBar.tsx | 2 +- client/src/components/TabRouter.tsx | 30 +++++++------- client/src/components/TabRouterHeader.tsx | 7 ++-- client/src/controllers/ProjectController.tsx | 12 ++++-- client/src/pages/ProjectPage.tsx | 4 +- client/src/pages/TicketPage.tsx | 2 +- client/src/types/User.ts | 1 + client/src/utils/router.tsx | 15 ++++--- client/src/viewModels/ProjectVM.ts | 11 +++-- 16 files changed, 73 insertions(+), 99 deletions(-) delete mode 100644 client/src/App.css diff --git a/client/src/App.css b/client/src/App.css deleted file mode 100644 index 90edddb..0000000 --- a/client/src/App.css +++ /dev/null @@ -1,42 +0,0 @@ -.panel { - padding-left: 0px; - padding-top: 10px; -} -.field { - padding-left: 10px; - padding-right: 10px; -} -.city { - display: flex; - background: linear-gradient( - 90deg, - rgba(2, 0, 36, 1) 0%, - rgba(25, 112, 245, 0.6399510487788865) 0%, - rgba(0, 212, 255, 1) 100% - ); - flex-direction: column; - height: 40vh; - justify-content: center; - align-items: center; - padding: 0px 20px 20px 20px; - margin: 0px 0px 50px 0px; - border: 1px solid; - border-radius: 5px; - box-shadow: 2px 2px #888888; - font-family: "Merriweather", serif; -} -.city h1 { - line-height: 1.2; -} -.city span { - padding-left: 20px; -} -.city .row { - padding-top: 20px; -} -.weatherError { - color: #f16051; - font-size: 20px; - letter-spacing: 1px; - font-weight: 200; -} diff --git a/client/src/App.tsx b/client/src/App.tsx index 2400e59..88220e3 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -1,6 +1,4 @@ import React, { FC } from "react"; -import { AppRouter } from "./utils/router"; -import "./App.css"; import Layout from "./pages/Layout"; const App: FC = () => { diff --git a/client/src/components/ActivityCollection.tsx b/client/src/components/ActivityCollection.tsx index e351219..1a3e506 100644 --- a/client/src/components/ActivityCollection.tsx +++ b/client/src/components/ActivityCollection.tsx @@ -9,8 +9,10 @@ export const ActivityCollection: FC = ({ activities }) => { return ( <>
      - {activities.map((f: Activity) => ( - + {activities.map((activity: Activity) => ( +
    • + +
    • ))}
    @@ -23,13 +25,13 @@ type IFProps = { export const ActivityEntry: FC = ({ activity }) => { return ( -
  • + <> {/* folder */} {activity.user.firstName} {activity.description} {activity.ticket.title}

    {activity.date.toDateString()}

    -
  • + ); }; diff --git a/client/src/components/AvatarList.tsx b/client/src/components/AvatarList.tsx index 7075728..48aacbf 100644 --- a/client/src/components/AvatarList.tsx +++ b/client/src/components/AvatarList.tsx @@ -1,15 +1,22 @@ import React, { FC } from "react"; -import { FloatingButton } from "./FloatingButton"; +import { User } from "../types/User"; interface AvatarListProps { - avatars: string[]; + users: User[]; } -export const AvatarList: FC = ({ avatars }) => { +export const AvatarList: FC = ({ users }) => { return ( <> - {avatars.map((avatar: string) => ( - + {users.map((user: User, i: number) => ( + {user.fullName} ))} ); diff --git a/client/src/components/Button.tsx b/client/src/components/Button.tsx index 0a42e10..8fc9f86 100644 --- a/client/src/components/Button.tsx +++ b/client/src/components/Button.tsx @@ -1,4 +1,4 @@ -import React, { FC, Children } from "react"; +import React, { FC } from "react"; interface IProps { icon?: string; diff --git a/client/src/components/FileCollection.tsx b/client/src/components/FileCollection.tsx index 158c1cb..582fe92 100644 --- a/client/src/components/FileCollection.tsx +++ b/client/src/components/FileCollection.tsx @@ -9,8 +9,8 @@ export const FileCollection: FC = ({ files }) => { return ( <>
      - {files.map((f: AppFile) => ( - + {files.map((file: AppFile) => ( + ))}
    @@ -23,7 +23,7 @@ type IFProps = { export const FileEntry: FC = ({ file }) => { return ( -
  • +
  • {/* */} folder {file.name} diff --git a/client/src/components/HorizontalCard.tsx b/client/src/components/HorizontalCard.tsx index 791222f..54d611e 100644 --- a/client/src/components/HorizontalCard.tsx +++ b/client/src/components/HorizontalCard.tsx @@ -1,5 +1,4 @@ import React, { FC, MouseEvent } from "react"; -import { AvatarList } from "./AvatarList"; import { Link } from "react-router-dom"; interface IProps { @@ -29,16 +28,16 @@ export const HorizontalCard: FC = ({
  • Due {remainingDays} days
    diff --git a/client/src/components/ProgressBar.tsx b/client/src/components/ProgressBar.tsx index a9324bb..1095cc9 100644 --- a/client/src/components/ProgressBar.tsx +++ b/client/src/components/ProgressBar.tsx @@ -1,4 +1,4 @@ -import React, { FC, HTMLAttributes, CSSProperties } from "react"; +import React, { FC, CSSProperties } from "react"; type ProgressBarProps = { value: number; diff --git a/client/src/components/TabRouter.tsx b/client/src/components/TabRouter.tsx index 6623285..9d7e55f 100644 --- a/client/src/components/TabRouter.tsx +++ b/client/src/components/TabRouter.tsx @@ -4,7 +4,7 @@ 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 { Route, useRouteMatch, Redirect } from "react-router-dom"; import { ActivityList } from "./ActivityList"; import { Activity } from "../types/Activity"; @@ -26,25 +26,23 @@ export const TabRouter: FC = ({ const { url } = useRouteMatch(); return ( <> - -
    - +
    + - + - - - + + + - - - + + + - - - -
    - + + + +
    ); }; diff --git a/client/src/components/TabRouterHeader.tsx b/client/src/components/TabRouterHeader.tsx index 0d8eb8f..5a95261 100644 --- a/client/src/components/TabRouterHeader.tsx +++ b/client/src/components/TabRouterHeader.tsx @@ -3,22 +3,21 @@ import { Link, useRouteMatch } from "react-router-dom"; interface IProps { tabClass?: string; - nTabs: number; tabNames: string[]; } export const TabRouterHeader: FC = ({ tabClass = "tab col s4", - nTabs, tabNames }) => { - const [isActive, setIsActive] = useState(0); - + const [isActive, setIsActive] = useState(0); + const nTabs = tabNames.length; return ( <>
      {tabNames.map((name, i) => ( { ticket: tickets[0] }, { - id: 3, + id: 2, description: " added the task ", date: new Date(), user: users[1], diff --git a/client/src/pages/ProjectPage.tsx b/client/src/pages/ProjectPage.tsx index f98d781..9e5b833 100644 --- a/client/src/pages/ProjectPage.tsx +++ b/client/src/pages/ProjectPage.tsx @@ -13,7 +13,7 @@ export const ProjectPage: FC = ({ viewModel }) => { const { title, description, - avatars, + users, value, tickets, ticketsDone, @@ -28,7 +28,7 @@ export const ProjectPage: FC = ({ viewModel }) => {
      - +
      { description="Research, ideate and present brand concepts for client consideration" title="Brand Concept and Design" /> - + {/* */} {/* // // diff --git a/client/src/types/User.ts b/client/src/types/User.ts index 88deb83..6869cd4 100644 --- a/client/src/types/User.ts +++ b/client/src/types/User.ts @@ -2,4 +2,5 @@ export interface User { id: string; picture: string; firstName: string; + fullName?: string; } diff --git a/client/src/utils/router.tsx b/client/src/utils/router.tsx index a90cafb..c2098ed 100644 --- a/client/src/utils/router.tsx +++ b/client/src/utils/router.tsx @@ -1,11 +1,16 @@ import React from "react"; -import { Router, Route, Switch, Link, NavLink } from "react-router-dom"; +import { + Router, + Route, + Switch + //Link, NavLink +} from "react-router-dom"; import * as creacteHistory from "history"; -import { TicketPage } from "../pages/TicketPage"; -import { HomeController } from "../controllers/HomeController"; +// import { TicketPage } from "../pages/TicketPage"; +// import { HomeController } from "../controllers/HomeController"; import { ProjectController } from "../controllers/ProjectController"; -import { UserController } from "../controllers/UserController"; -import { TicketController } from "../controllers/TicketController"; +// import { UserController } from "../controllers/UserController"; +// import { TicketController } from "../controllers/TicketController"; export const history = creacteHistory.createBrowserHistory(); diff --git a/client/src/viewModels/ProjectVM.ts b/client/src/viewModels/ProjectVM.ts index 490a10a..d660db6 100644 --- a/client/src/viewModels/ProjectVM.ts +++ b/client/src/viewModels/ProjectVM.ts @@ -1,9 +1,10 @@ import { Ticket } from "../types/Ticket"; import { Project } from "../types/Project"; -import { Constants } from "../utils/Constants"; -import { User } from "../types/User"; +// import { Constants } from "../utils/Constants"; +// import { User } from "../types/User"; import { AppFile } from "../types/AppFile"; import { Activity } from "../types/Activity"; +import { User } from "../types/User"; export default class ProjectVM { public id: number; @@ -11,7 +12,8 @@ export default class ProjectVM { public description: string; public value: number; public tickets: Ticket[]; - public avatars: string[]; + // public avatars: string[]; + public users: User[]; public ticketsTotalCount: number; public ticketsDone: number; public remainingDays: number; @@ -33,7 +35,8 @@ export default class ProjectVM { this.id = project.id; this.title = project.title; this.description = project.description; - this.avatars = project.users.map(u => u.picture); + // this.avatars = project.users.map(u => u.picture); + this.users = project.users; this.value = project.progression; this.tickets = project.tickets; this.ticketsTotalCount = this.tickets.length; From 24196274004775c84eb03bee86c331ac133e728b Mon Sep 17 00:00:00 2001 From: Ruidy Nemausat Date: Thu, 20 Feb 2020 17:50:14 +0100 Subject: [PATCH 11/21] Add input File design, filtering for project page tabs --- client/src/components/ActivityList.tsx | 14 ++++- client/src/components/AppFileList.tsx | 17 ++++-- client/src/components/DropZone.tsx | 7 --- client/src/components/FilterBar.tsx | 39 +++++++++++++ client/src/components/HorizontalCard.tsx | 5 +- client/src/components/InputFile.tsx | 29 ++++++++++ client/src/components/TabRouter.tsx | 3 +- client/src/components/TicketList.tsx | 58 +++++++++++++++----- client/src/controllers/ProjectController.tsx | 8 ++- client/src/index.css | 13 ----- client/src/index.tsx | 1 - client/src/pages/ProjectPage.tsx | 1 - client/src/types/Ticket.ts | 2 + client/src/utils/methods.ts | 7 +++ client/src/viewModels/ProjectVM.ts | 11 +--- 15 files changed, 156 insertions(+), 59 deletions(-) delete mode 100644 client/src/components/DropZone.tsx create mode 100644 client/src/components/FilterBar.tsx create mode 100644 client/src/components/InputFile.tsx delete mode 100644 client/src/index.css create mode 100644 client/src/utils/methods.ts diff --git a/client/src/components/ActivityList.tsx b/client/src/components/ActivityList.tsx index 010f727..969b7ff 100644 --- a/client/src/components/ActivityList.tsx +++ b/client/src/components/ActivityList.tsx @@ -1,18 +1,26 @@ -import React, { FC } from "react"; -import { FloatingButton } from "./FloatingButton"; +import React, { FC, useState, ChangeEvent } from "react"; import { ActivityCollection } from "./ActivityCollection"; import { Activity } from "../types/Activity"; +import { FilterBar } from "./FilterBar"; type IProps = { activities: Activity[]; }; export const ActivityList: FC = ({ activities }) => { + const [filterText, setFilterText] = useState(""); + + const handleChange: (e: ChangeEvent) => void = ( + e: ChangeEvent + ) => { + setFilterText(e.target.value); + }; + return ( <>

      Activity

      - +
      diff --git a/client/src/components/AppFileList.tsx b/client/src/components/AppFileList.tsx index 449ec93..9f85093 100644 --- a/client/src/components/AppFileList.tsx +++ b/client/src/components/AppFileList.tsx @@ -1,21 +1,28 @@ -import React, { FC } from "react"; +import React, { FC, useState, ChangeEvent } from "react"; import { AppFile } from "../types/AppFile"; -import { FloatingButton } from "./FloatingButton"; import { FileCollection } from "./FileCollection"; -import { DropZone } from "./DropZone"; +import { InputFile } from "./InputFile"; +import { FilterBar } from "./FilterBar"; type IProps = { files: AppFile[]; }; export const FileList: FC = ({ files }) => { + const [filterText, setFilterText] = useState(""); + + const handleChange: (e: ChangeEvent) => void = ( + e: ChangeEvent + ) => { + setFilterText(e.target.value); + }; return ( <>

      Files

      - +
      - + ); diff --git a/client/src/components/DropZone.tsx b/client/src/components/DropZone.tsx deleted file mode 100644 index 4ff5146..0000000 --- a/client/src/components/DropZone.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import React, { FC } from "react"; - -type IProps = {}; - -export const DropZone: FC = () => { - return
      Drag & Drop your files here.
      ; -}; diff --git a/client/src/components/FilterBar.tsx b/client/src/components/FilterBar.tsx new file mode 100644 index 0000000..62754c7 --- /dev/null +++ b/client/src/components/FilterBar.tsx @@ -0,0 +1,39 @@ +import React, { FC } from "react"; +import { useRouteMatch } from "react-router-dom"; + +type IProps = { + filterText: string; + handleChange: (e: React.ChangeEvent) => void; +}; + +export const FilterBar: FC = ({ filterText, handleChange }) => { + const { url } = useRouteMatch(); + const placeholder: string = url.split("/")[3]; + return ( + <> +
      +
      + + + + close + +
      +
      +
      + + ); +}; diff --git a/client/src/components/HorizontalCard.tsx b/client/src/components/HorizontalCard.tsx index 54d611e..f9b7f2c 100644 --- a/client/src/components/HorizontalCard.tsx +++ b/client/src/components/HorizontalCard.tsx @@ -1,9 +1,10 @@ import React, { FC, MouseEvent } from "react"; import { Link } from "react-router-dom"; +import { getRemainingdays } from "../utils/methods"; interface IProps { title: string; - remainingDays?: number; + remainingDays: string; validateTicket: (event: MouseEvent) => void; archiveTicket: (event: MouseEvent) => void; } @@ -26,7 +27,7 @@ export const HorizontalCard: FC = ({
      - Due {remainingDays} days + Due {getRemainingdays(remainingDays)} days
      diff --git a/client/src/components/InputFile.tsx b/client/src/components/InputFile.tsx new file mode 100644 index 0000000..aa528e9 --- /dev/null +++ b/client/src/components/InputFile.tsx @@ -0,0 +1,29 @@ +import React, { FC } from "react"; + +type IProps = {}; + +export const InputFile: FC = () => { + return ( + <> +
      +
      +
      + cloud_upload + +
      +
      + +
      +
      +
      + + ); +}; diff --git a/client/src/components/TabRouter.tsx b/client/src/components/TabRouter.tsx index 9d7e55f..3b3915e 100644 --- a/client/src/components/TabRouter.tsx +++ b/client/src/components/TabRouter.tsx @@ -18,7 +18,6 @@ interface IProps { export const TabRouter: FC = ({ tickets, - remainingDays, tabNames, files, activities @@ -32,7 +31,7 @@ export const TabRouter: FC = ({ - + diff --git a/client/src/components/TicketList.tsx b/client/src/components/TicketList.tsx index df56bb0..c810fcd 100644 --- a/client/src/components/TicketList.tsx +++ b/client/src/components/TicketList.tsx @@ -1,35 +1,65 @@ -import React, { FC } from "react"; +import React, { FC, useState, ChangeEvent } from "react"; import { Ticket } from "../types/Ticket"; import { FloatingButton } from "./FloatingButton"; import { HorizontalCard } from "./HorizontalCard"; +import { FilterBar } from "./FilterBar"; type TicketListProps = { tickets: Ticket[]; - remainingDays?: number; }; -export const TicketList: FC = ({ tickets, remainingDays }) => { +export const TicketList: FC = ({ tickets }) => { const archiveTicket = () => {}; const validateTicket = () => {}; + const [filterText, setFilterText] = useState(""); + const handleChange: (e: ChangeEvent) => void = ( + e: ChangeEvent + ) => { + setFilterText(e.target.value); + }; + + // const useFilter = (init: string) => { + // const [filterText, setFilterText] = useState(init); + // // const handleChange: (e: ChangeEvent) => void = ( + // // e: ChangeEvent + // // ) => { + // // setFilterText(e.target.value); + // // }; + // return { + // filterText, + // setFilterText, + // bind: { + // filterText, + // handleChange: (e: ChangeEvent) => { + // setFilterText(e.target.value); + // } + // } + // }; + // }; + // const [filterText, handleChange] = useFilter(""); + // const [filterText, handleChange] = useFilter(""); return ( <>

      Tickets

      - + +
        - {tickets.map((t: Ticket) => ( -
      • - -
      • - ))} + {tickets + .filter(t => t.title.includes(filterText)) + .map((t: Ticket) => ( +
      • + +
      • + ))}
      diff --git a/client/src/controllers/ProjectController.tsx b/client/src/controllers/ProjectController.tsx index 86a6d64..9999fde 100644 --- a/client/src/controllers/ProjectController.tsx +++ b/client/src/controllers/ProjectController.tsx @@ -37,12 +37,16 @@ export const ProjectController: FC = () => { const tickets: Ticket[] = [ { id: 1, - title: "Ticket #1", + title: "Client objective meeting", + description: "Client objective meeting", + plannedEnding: "2020-02-17 15:51:02.787373", status: "Done" }, { id: 2, - title: "Ticket #2", + title: "Assemble Outcomes Report for client", + description: "Assemble Outcomes Report for client", + plannedEnding: "2020-02-27 15:51:02.787373", status: "To Do" } ]; diff --git a/client/src/index.css b/client/src/index.css deleted file mode 100644 index ec2585e..0000000 --- a/client/src/index.css +++ /dev/null @@ -1,13 +0,0 @@ -body { - margin: 0; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -code { - font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', - monospace; -} diff --git a/client/src/index.tsx b/client/src/index.tsx index 90fb3f6..8780a3a 100644 --- a/client/src/index.tsx +++ b/client/src/index.tsx @@ -1,6 +1,5 @@ import React from "react"; import ReactDOM from "react-dom"; -import "./index.css"; import App from "./App"; import * as serviceWorker from "./serviceWorker"; diff --git a/client/src/pages/ProjectPage.tsx b/client/src/pages/ProjectPage.tsx index 9e5b833..8c49f6b 100644 --- a/client/src/pages/ProjectPage.tsx +++ b/client/src/pages/ProjectPage.tsx @@ -41,7 +41,6 @@ export const ProjectPage: FC = ({ viewModel }) => { tabNames={tabNames} tickets={tickets} files={files} - remainingDays={remainingDays} activities={activities} />
      diff --git a/client/src/types/Ticket.ts b/client/src/types/Ticket.ts index a258326..7d675b1 100644 --- a/client/src/types/Ticket.ts +++ b/client/src/types/Ticket.ts @@ -1,5 +1,7 @@ export interface Ticket { id: number; title: string; + description: string; status: string; + plannedEnding: string; } diff --git a/client/src/utils/methods.ts b/client/src/utils/methods.ts new file mode 100644 index 0000000..8051548 --- /dev/null +++ b/client/src/utils/methods.ts @@ -0,0 +1,7 @@ +export const getRemainingdays: (endDate: string) => number = ( + endDate: string +) => { + let endingDate: Date = new Date(endDate); + let today: Date = new Date(); + return Math.abs(endingDate.getDate() - today.getDate()); +}; diff --git a/client/src/viewModels/ProjectVM.ts b/client/src/viewModels/ProjectVM.ts index d660db6..505e1c9 100644 --- a/client/src/viewModels/ProjectVM.ts +++ b/client/src/viewModels/ProjectVM.ts @@ -5,6 +5,7 @@ import { Project } from "../types/Project"; import { AppFile } from "../types/AppFile"; import { Activity } from "../types/Activity"; import { User } from "../types/User"; +import { getRemainingdays } from "../utils/methods"; export default class ProjectVM { public id: number; @@ -12,7 +13,6 @@ export default class ProjectVM { public description: string; public value: number; public tickets: Ticket[]; - // public avatars: string[]; public users: User[]; public ticketsTotalCount: number; public ticketsDone: number; @@ -35,7 +35,6 @@ export default class ProjectVM { this.id = project.id; this.title = project.title; this.description = project.description; - // this.avatars = project.users.map(u => u.picture); this.users = project.users; this.value = project.progression; this.tickets = project.tickets; @@ -43,12 +42,6 @@ export default class ProjectVM { 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; + this.remainingDays = getRemainingdays(project.plannedEnding); } } From 4b43486c168e13dac5b4f9d7e23aaf1c8930c5bc Mon Sep 17 00:00:00 2001 From: Ruidy Nemausat Date: Fri, 21 Feb 2020 11:32:10 +0100 Subject: [PATCH 12/21] changed background color & enhanced filtering --- client/src/components/ActivityCollection.tsx | 22 ++++++++++++++------ client/src/components/ActivityList.tsx | 14 +++++++++---- client/src/components/AppFileList.tsx | 14 +++++++++---- client/src/components/FileCollection.tsx | 15 +++++++++---- client/src/components/FilterBar.tsx | 16 +++++++------- client/src/components/TicketList.tsx | 17 +++++++++++---- client/src/controllers/ProjectController.tsx | 2 +- client/src/utils/router.tsx | 2 +- 8 files changed, 71 insertions(+), 31 deletions(-) diff --git a/client/src/components/ActivityCollection.tsx b/client/src/components/ActivityCollection.tsx index 1a3e506..dc599dc 100644 --- a/client/src/components/ActivityCollection.tsx +++ b/client/src/components/ActivityCollection.tsx @@ -3,17 +3,27 @@ import { Activity } from "../types/Activity"; type IProps = { activities: Activity[]; + filterText: string; }; -export const ActivityCollection: FC = ({ activities }) => { +export const ActivityCollection: FC = ({ activities, filterText }) => { return ( <>
        - {activities.map((activity: Activity) => ( -
      • - -
      • - ))} + {activities + .filter( + a => + a.description.toLowerCase().includes(filterText.toLowerCase()) || + a.user.firstName + .toLowerCase() + .includes(filterText.toLowerCase()) || + a.ticket.title.toLowerCase().includes(filterText.toLowerCase()) + ) + .map((activity: Activity) => ( +
      • + +
      • + ))}
      ); diff --git a/client/src/components/ActivityList.tsx b/client/src/components/ActivityList.tsx index 969b7ff..5f597c0 100644 --- a/client/src/components/ActivityList.tsx +++ b/client/src/components/ActivityList.tsx @@ -1,4 +1,4 @@ -import React, { FC, useState, ChangeEvent } from "react"; +import React, { FC, useState, ChangeEvent, MouseEvent } from "react"; import { ActivityCollection } from "./ActivityCollection"; import { Activity } from "../types/Activity"; import { FilterBar } from "./FilterBar"; @@ -9,7 +9,9 @@ type IProps = { export const ActivityList: FC = ({ activities }) => { const [filterText, setFilterText] = useState(""); - + const clearFilterText: (e: MouseEvent) => void = (e: MouseEvent) => { + setFilterText(""); + }; const handleChange: (e: ChangeEvent) => void = ( e: ChangeEvent ) => { @@ -20,9 +22,13 @@ export const ActivityList: FC = ({ activities }) => { <>

      Activity

      - +
      - + ); }; diff --git a/client/src/components/AppFileList.tsx b/client/src/components/AppFileList.tsx index 9f85093..fd4cd63 100644 --- a/client/src/components/AppFileList.tsx +++ b/client/src/components/AppFileList.tsx @@ -1,4 +1,4 @@ -import React, { FC, useState, ChangeEvent } from "react"; +import React, { FC, useState, ChangeEvent, MouseEvent } from "react"; import { AppFile } from "../types/AppFile"; import { FileCollection } from "./FileCollection"; import { InputFile } from "./InputFile"; @@ -10,7 +10,9 @@ type IProps = { export const FileList: FC = ({ files }) => { const [filterText, setFilterText] = useState(""); - + const clearFilterText: (e: MouseEvent) => void = (e: MouseEvent) => { + setFilterText(""); + }; const handleChange: (e: ChangeEvent) => void = ( e: ChangeEvent ) => { @@ -20,10 +22,14 @@ export const FileList: FC = ({ files }) => { <>

      Files

      - +
      - + ); }; diff --git a/client/src/components/FileCollection.tsx b/client/src/components/FileCollection.tsx index 582fe92..114ae98 100644 --- a/client/src/components/FileCollection.tsx +++ b/client/src/components/FileCollection.tsx @@ -3,15 +3,22 @@ import { AppFile } from "../types/AppFile"; type IProps = { files: AppFile[]; + filterText: string; }; -export const FileCollection: FC = ({ files }) => { +export const FileCollection: FC = ({ files, filterText }) => { return ( <>
        - {files.map((file: AppFile) => ( - - ))} + {files + .filter( + f => + f.name.toLowerCase().includes(filterText.toLowerCase()) || + f.format.toLowerCase().includes(filterText.toLowerCase()) + ) + .map((file: AppFile) => ( + + ))}
      ); diff --git a/client/src/components/FilterBar.tsx b/client/src/components/FilterBar.tsx index 62754c7..a99b24e 100644 --- a/client/src/components/FilterBar.tsx +++ b/client/src/components/FilterBar.tsx @@ -1,12 +1,17 @@ -import React, { FC } from "react"; +import React, { FC, ChangeEvent, MouseEvent } from "react"; import { useRouteMatch } from "react-router-dom"; type IProps = { filterText: string; - handleChange: (e: React.ChangeEvent) => void; + handleChange: (e: ChangeEvent) => void; + clearFilterText: (e: MouseEvent) => void; }; -export const FilterBar: FC = ({ filterText, handleChange }) => { +export const FilterBar: FC = ({ + filterText, + handleChange, + clearFilterText +}) => { const { url } = useRouteMatch(); const placeholder: string = url.split("/")[3]; return ( @@ -26,13 +31,10 @@ export const FilterBar: FC = ({ filterText, handleChange }) => { - + close
    -
    ); diff --git a/client/src/components/TicketList.tsx b/client/src/components/TicketList.tsx index c810fcd..5864041 100644 --- a/client/src/components/TicketList.tsx +++ b/client/src/components/TicketList.tsx @@ -1,4 +1,4 @@ -import React, { FC, useState, ChangeEvent } from "react"; +import React, { FC, useState, ChangeEvent, MouseEvent } from "react"; import { Ticket } from "../types/Ticket"; import { FloatingButton } from "./FloatingButton"; import { HorizontalCard } from "./HorizontalCard"; @@ -9,9 +9,12 @@ type TicketListProps = { }; export const TicketList: FC = ({ tickets }) => { + const [filterText, setFilterText] = useState(""); + const clearFilterText: (e: MouseEvent) => void = (e: MouseEvent) => { + setFilterText(""); + }; const archiveTicket = () => {}; const validateTicket = () => {}; - const [filterText, setFilterText] = useState(""); const handleChange: (e: ChangeEvent) => void = ( e: ChangeEvent @@ -44,12 +47,18 @@ export const TicketList: FC = ({ tickets }) => {

    Tickets

    - +
      {tickets - .filter(t => t.title.includes(filterText)) + .filter(t => + t.title.toLowerCase().includes(filterText.toLowerCase()) + ) .map((t: Ticket) => (
    • { name: "Business Model Canvas", description: "Path to 1B$", size: 2100, - format: "pdf" + format: "png" } ]; diff --git a/client/src/utils/router.tsx b/client/src/utils/router.tsx index c2098ed..7f8078e 100644 --- a/client/src/utils/router.tsx +++ b/client/src/utils/router.tsx @@ -17,7 +17,7 @@ export const history = creacteHistory.createBrowserHistory(); export const AppRouter = () => { return ( -
      +
      {/* From 5d0c8edacd1c3791fe51a5f660d8473d254b4446 Mon Sep 17 00:00:00 2001 From: Ruidy Nemausat Date: Fri, 21 Feb 2020 12:00:27 +0100 Subject: [PATCH 13/21] project page connected to API without authentication. Undefined data Errors handled --- client/src/components/ActivityCollection.tsx | 4 +- client/src/components/AvatarList.tsx | 4 +- client/src/controllers/ProjectController.tsx | 245 +++++++++---------- client/src/utils/Constants.ts | 2 +- client/src/viewModels/ProjectVM.ts | 21 +- 5 files changed, 134 insertions(+), 142 deletions(-) diff --git a/client/src/components/ActivityCollection.tsx b/client/src/components/ActivityCollection.tsx index dc599dc..b37d8ac 100644 --- a/client/src/components/ActivityCollection.tsx +++ b/client/src/components/ActivityCollection.tsx @@ -7,7 +7,9 @@ type IProps = { }; export const ActivityCollection: FC = ({ activities, filterText }) => { - return ( + return activities === undefined ? ( + <> + ) : ( <>
        {activities diff --git a/client/src/components/AvatarList.tsx b/client/src/components/AvatarList.tsx index 48aacbf..33dc256 100644 --- a/client/src/components/AvatarList.tsx +++ b/client/src/components/AvatarList.tsx @@ -6,7 +6,9 @@ interface AvatarListProps { } export const AvatarList: FC = ({ users }) => { - return ( + return users === undefined ? ( + <> + ) : ( <> {users.map((user: User, i: number) => ( { - // const [project, setProject] = useState({} as Project); - const [isLoading, setIsLoading] = useState(false); + const [project, setProject] = useState({} as Project); + const [isLoading, setIsLoading] = useState(true); + const { id } = useParams(); - // const { id } = useParams(); + const getProject: (id: number) => void = (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); - // }, [id]); + useEffect(() => { + if (id !== undefined) { + getProject(parseInt(id)); + } + }, [id]); // const viewModel = new ProjectVM(project); - const tickets: Ticket[] = [ - { - id: 1, - title: "Client objective meeting", - description: "Client objective meeting", - plannedEnding: "2020-02-17 15:51:02.787373", - status: "Done" - }, - { - id: 2, - title: "Assemble Outcomes Report for client", - description: "Assemble Outcomes Report for client", - plannedEnding: "2020-02-27 15:51:02.787373", - status: "To Do" - } - ]; + // const tickets: Ticket[] = [ + // { + // id: 1, + // title: "Client objective meeting", + // description: "Client objective meeting", + // plannedEnding: "2020-02-17 15:51:02.787373", + // status: "Done" + // }, + // { + // id: 2, + // title: "Assemble Outcomes Report for client", + // description: "Assemble Outcomes Report for client", + // plannedEnding: "2020-02-27 15:51:02.787373", + // status: "To Do" + // } + // ]; - const users: User[] = [ - { - id: "1", - firstName: "PacMan", - picture: - "data:image/jpeg;base64,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" - }, - { - id: "2", - firstName: "Avatar", - picture: - "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAMAAACahl6sAAAAM1BMVEUKME7///+El6bw8vQZPVlHZHpmfpHCy9Ojsbzg5ekpSmTR2N44V29XcYayvsd2i5yTpLFbvRYnAAAJcklEQVR4nO2d17arOgxFs+kkofz/154Qmg0uKsuQccddT/vhnOCJLclFMo+//4gedzcApf9B4srrusk+GsqPpj+ypq7zVE9LAdLWWVU+Hx69y2FMwAMGyfusLHwIpooyw9IAQfK+8naDp3OGHvZ0FMhrfPMgVnVjC2kABOQ1MLvi0DEIFj1ILu0LU2WjNRgtSF3pKb4qqtd9IHmjGlJHlc09IHlGcrQcPeUjTAySAGNSkQlRhCCJMGaUC0HSYUx6SmxFAtJDTdylsr4ApC1TY0yquKbCBkk7qnYVzPHFBHkBojhVJWviwgPJrsP4qBgTgbQXdsesjm4pDJDmIuswVZDdFx0ENTtkihoeqSDXD6tVxOFFBHndMKxWvUnzexpIcx/Gg2goJJDhVo6PCMGRAnKTmZuKm3wcJO/upphUqUHy29yVrRhJDORXOKIkEZDf4YiRhEF+iSNCEgb5KY4wSRDkB/yurUEG8nMcocgYABnvbrVL3nMIP0h/d5udKnwzSC/InfPdkJ6eWb0PJE++dyVVyQP5iQmWW27X5QG5druEKafBu0Hqu9saVOHa8HKC/K6BzHKZiRMEZCDF0Nd1/ZfXI/fcOibHOssFgokg9uFA20BhztHEAZIjIohrD/o1wljeFBDEwBo8YUt5Ir/rNLjOIACPFdy/AbEcPdcJBOCxytjeYAM4Kzp6rhOIPhRGNzwmFP3rOoTFI0irtnQKx6fj1Zt+h9njEUS9mKJxfFRrX5lt7wcQtaWTOfTHeIXVJQcQrRW+OYex2j0a66XZINoO8a7fPH2iHF2mC7ZBtB3Czb5QvjizSx7A3308mRzqAwujSywQbYfwc0iU8zqjS0yQ6ztEHX9332KCaGNIYB/Qq1z3yN0oDZBWyeFYJBCkm2sXLhDtpKFwNDMu5TnrZpYGiHbK4Nlwikg5DrYV1g6iPoJmzE5MKd/fOp53EPUaQZaLqH3u+vo2ELWp3wSyWuYGoj9EEIJoV3L9AUS/ZLsJpLNBXmqOu0CW6P5A/dx9IL0FAji/FYKot9EqE0Tvs6QBUe/2CxMEkZAlBNGPhdoAQWyTSmbxUwvUygwQyMmniAPgLt87CODXHuftWJIQgzrfQDC5AfwSgz9MmmG/gWCOqDgZ4JsQeTvZBoJJDhAFEsSDyxUEEUUekk0UEMhjBcEcGsoWVpBU3NcCgkkPkJWrKbdRZvULCMTWhYEdMrayBQRyqHcnSLmAIH7LcWJ8Hch7BsHEdWFpJsZjziCgFBpZ9TPm4e0XBJTTJKt9xjy8RoLI4gimPLP5goCSgWTrEcyzsy8IqmZVMo0H5bJiQToBCOjZ5RcElhjLN3dU7uQMAvoxwQkJZKI1CQzCthJYEigahHuDDi4rFwzCPQ7F1fiDQZgTR5iJwEGYRgIsiECD8BwwMAEfDcIaW8CRBQdhjS1kJQEchDEFhiRKr4KDFPS9FGQNVwEHoW83QjsEHdkfnuIOl6C1NjMItiaCaCWgbdpFJXQ9soh2uoB9aJcCxFdgZwlcrTmvENGlrITBBdpK25Qhd1F2RScq8CKu/gsCL8qN5THjy+Rr5E6joYgPxpdl518QrCf8Kpgjn6C8HLkbb+vt7ZM8wdVvy258khsRfHaS5DalDnlidZT7Erk+SXV5Bj1D3LS29XyhVJuoKHs9Q8S6reK11oUc7vPcr9uswP3SLiDINefXOF5rwCuGzVT6zVkVPfh2wWmHcz4wAwba2cgN1/Tsvleu7//i69CgVyt1GwjOs2+XK3rtbl151Tg3vOeioG40Mz2V+6pQ4xbJHOZj6g0EMxk93tV7fuedvVZpQSPhbwNBGInrymGrwNh1GXmL8F+lAaJ+NU/fzcmvJqvKj7177+1v1GY/GiBKI1Fdy/2XK6upXwaIJpI8B/399W0mH9zzafKaeCF9J0WF+jyCuFusTGzZKhFH8dVLZql2brxgcdVBKb7KG/7UZTmB3XJ6uL/QYT5ScRI74FcHEJ7feopyfGkaeaGlPoCw/BbjZmSBWIvINQNmTxdjWJqwUI8sztR4nYPuIPSTSUnOCZOE3ierqRoJfNSQxDjLEYs8i91eqgFCDSWiFHiuqAN9CwEGCPEISVjvwhS7Mfx6dtX8kC5aqvneGBOEFN2v6RBiYwr3DQOkLhEW6fHFbIwFQnkLiWYmZxE220z/aedPx99C+hiyKR4OzNFhg8S75CJTnxQ1dyugHTLaY10iu9dBpmhQtMz1ABLrkgtHVnRsPUO3OcU25i8cWdGxZbflCBKJqBdMs3aF/dYhNexU9RFcYEmLXYQKghyWdufyldBSU3KpjkKhZclxTXQGCTkL/HZDUIH5+Gkt4SgoCtj7pSYSNJLTK3VVRnmXZxebSMBIzmHABeIdXBebiN9eHYtUZ62ab3BdGkUm+SKJw1bdRXeewaX7qqdAnljg2sVxg3guAk3baofcg9yZ2eZpnHNvSFrEqhB9YPjesmt0pt6Xc8hl7W5L9Q4Xx09ctsrd5VhWeF6nF8SRrZdw49qns//0xTK/AZ8vGr3caTliuzeFNeCJTgafpKlhHd2WP1sy1LqDF798gjKJPLqDr9keoTd43+NyNzC1CI8Xy2lcPtOaVBI5IiAWyQ3e125AcKoXs2Djhy5eVc3KiBxREIPkhjBiLhIjU++4T91IbggjRiCJLSEIwWGddkEaxlVN5KCArPHk8mXVpHk8FHH7JL3n5dPA7C90q7XkeFJucacNmGXeRfswLE71HA79efaGiCN/Ofjmfmtcp8X10tIsqCacV5xfRWjNUiXGYbovWgyFYHcQLak15K9oM5zqmgaeKsHJetbSHfSPzXOiw/rxE9YH4CXaUpsZ0ztemFurP95Jpyvrd29YTpIZr7cEJHqfc7Wl0PFm2+yJR70udaokKFtGPTdm8WdQe24+HmVLlueboWQquBcYYVH2vEzfh8kCks1p90eWsLCyZ8qK7E86Oe+3XYFnBuiWdth20UqZR5SvMoyPg3WNauJipi0LMTQgVq5xUUlZcrPsopPHJ926z8pm7xyFLrH/PxpHSoXKdWgXsLn1scZn1ZDd/2vszN3lt254qkE+qu3yoqLM+ghN3Qz2qcVzUC/ZMFsK/alU6l0OWV/bQz6v6yYbyuN5BaZ4A7Y30vs/PPksS2+qzlvfF7OQmzzcL7W+xa7OIfRuVdtn/tdvdFLnL4OTKcm2W16PmWc4FWWXNSlWM2n3D+uPxuyrcfo74aP+Ac30a82+oLmfAAAAAElFTkSuQmCC" - }, - { - id: "3", - firstName: "Zoey", - picture: - "data:image/jpeg;base64,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" - }, - { - id: "4", - firstName: "Kory", - picture: - "data:image/jpeg;base64,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" - } - ]; + // const users: User[] = [ + // { + // id: "1", + // firstName: "PacMan", + // picture: + // "data:image/jpeg;base64,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" + // }, + // { + // id: "2", + // firstName: "Avatar", + // picture: + // "data:image/png;base64,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" + // }, + // { + // id: "3", + // firstName: "Zoey", + // picture: + // "data:image/jpeg;base64,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" + // }, + // { + // id: "4", + // firstName: "Kory", + // picture: + // "data:image/jpeg;base64,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" + // } + // ]; - const files: AppFile[] = [ - { - id: 1, - name: "SRS", - description: "App blueprint", - size: 15, - format: "pdf" - }, - { - id: 2, - name: "Business Model Canvas", - description: "Path to 1B$", - size: 2100, - format: "png" - } - ]; + // const files: AppFile[] = [ + // { + // id: 1, + // name: "SRS", + // description: "App blueprint", + // size: 15, + // format: "pdf" + // }, + // { + // id: 2, + // name: "Business Model Canvas", + // description: "Path to 1B$", + // size: 2100, + // format: "png" + // } + // ]; - const activities: Activity[] = [ - { - id: 1, - description: " completed the task ", - date: new Date(), - user: users[0], - ticket: tickets[0] - }, - { - id: 2, - description: " added the task ", - date: new Date(), - user: users[1], - ticket: tickets[1] - }, - { - id: 3, - description: " rescheduled the task ", - date: new Date(), - user: users[2], - ticket: tickets[1] - }, - { - id: 4, - description: " added the task ", - date: new Date(), - user: users[3], - ticket: tickets[0] - } - ]; - const project: Project = { - id: 1, - title: "Project Title", - description: "What is it about", - progression: 25, - tickets: tickets, - users: users, - plannedEnding: "2020-02-17 15:51:02.787373", - files: files, - activities: activities - }; + // const activities: Activity[] = [ + // { + // id: 1, + // description: " completed the task ", + // date: new Date(), + // user: users[0], + // ticket: tickets[0] + // }, + // { + // id: 2, + // description: " added the task ", + // date: new Date(), + // user: users[1], + // ticket: tickets[1] + // }, + // { + // id: 3, + // description: " rescheduled the task ", + // date: new Date(), + // user: users[2], + // ticket: tickets[1] + // }, + // { + // id: 4, + // description: " added the task ", + // date: new Date(), + // user: users[3], + // ticket: tickets[0] + // } + // ]; + // const project: Project = { + // id: 1, + // title: "Project Title", + // description: "What is it about", + // progression: 25, + // tickets: tickets, + // users: users, + // plannedEnding: "2020-02-17 15:51:02.787373", + // files: files, + // activities: activities + // }; const viewModel = new ProjectVM(project); diff --git a/client/src/utils/Constants.ts b/client/src/utils/Constants.ts index f889fc4..e714aa1 100644 --- a/client/src/utils/Constants.ts +++ b/client/src/utils/Constants.ts @@ -1,3 +1,3 @@ export class Constants { - static getProjectURI: string = "/api/projects"; + static getProjectURI: string = "/api/v1/projects"; } diff --git a/client/src/viewModels/ProjectVM.ts b/client/src/viewModels/ProjectVM.ts index 505e1c9..717a233 100644 --- a/client/src/viewModels/ProjectVM.ts +++ b/client/src/viewModels/ProjectVM.ts @@ -1,7 +1,5 @@ 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"; import { User } from "../types/User"; @@ -20,17 +18,6 @@ export default class ProjectVM { public files: AppFile[]; public activities: Activity[]; - /** - * getMembers - */ - // public getMembers(): string { - // let res: Promise = fetch( - // `${Constants.getProjectURI}/${this.id}/members` - // ); - // return JSON.stringify(res); - // // res.json(); - // } - public constructor(project: Project) { this.id = project.id; this.title = project.title; @@ -38,8 +25,12 @@ export default class ProjectVM { this.users = project.users; this.value = project.progression; this.tickets = project.tickets; - this.ticketsTotalCount = this.tickets.length; - this.ticketsDone = this.tickets.filter(t => t.status === "Done").length; + this.ticketsTotalCount = + this.tickets === undefined ? 0 : this.tickets.length; + this.ticketsDone = + this.tickets === undefined + ? 0 + : this.tickets.filter(t => t.status === "Done").length; this.files = project.files; this.activities = project.activities; this.remainingDays = getRemainingdays(project.plannedEnding); From 2343747b1c55e90e2e907f9f0701c6e00680617e Mon Sep 17 00:00:00 2001 From: Ruidy Nemausat Date: Fri, 21 Feb 2020 13:57:03 +0100 Subject: [PATCH 14/21] projectDTO created. Changed entity name History to Activity --- Controllers/HistoriesController.cs | 110 ----------------------------- Controllers/ProjectsController.cs | 14 ++-- Data/AppDbContext.cs | 2 +- Data/AppUserRepository.cs | 2 +- DataTransfertObjects/ProjectDTO.cs | 47 ++++++++++++ Models/{History.cs => Activity.cs} | 3 +- Models/AppUser.cs | 2 +- Models/Interfaces/ITask.cs | 6 +- Models/Project.cs | 3 +- Models/Ticket.cs | 2 +- client/src/types/Activity.ts | 3 + client/src/types/History.ts | 3 - client/src/types/Project.ts | 12 +++- 13 files changed, 78 insertions(+), 131 deletions(-) delete mode 100644 Controllers/HistoriesController.cs create mode 100644 DataTransfertObjects/ProjectDTO.cs rename Models/{History.cs => Activity.cs} (86%) create mode 100644 client/src/types/Activity.ts delete mode 100644 client/src/types/History.ts diff --git a/Controllers/HistoriesController.cs b/Controllers/HistoriesController.cs deleted file mode 100644 index 67eee4a..0000000 --- a/Controllers/HistoriesController.cs +++ /dev/null @@ -1,110 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; -using Microsoft.EntityFrameworkCore; -using TicketManager.Data; -using TicketManager.Models; - -namespace TicketManager.Controllers -{ - [Authorize] - [Route("api/v1/[controller]")] - [ApiController] - public class HistoriesController : ControllerBase - { - private readonly AppDbContext _context; - - public HistoriesController(AppDbContext context) - { - _context = context; - } - - // GET: api/Histories - [HttpGet] - public async Task>> GetEdits() - { - return await _context.Edits.ToListAsync(); - } - - // GET: api/Histories/5 - [HttpGet("{id}")] - public async Task> GetHistory(int id) - { - var history = await _context.Edits.FindAsync(id); - - if (history == null) - { - return NotFound(); - } - - return history; - } - - // PUT: api/Histories/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 PutHistory(int id, History history) - { - if (id != history.Id) - { - return BadRequest(); - } - - _context.Entry(history).State = EntityState.Modified; - - try - { - await _context.SaveChangesAsync(); - } - catch (DbUpdateConcurrencyException) - { - if (!HistoryExists(id)) - { - return NotFound(); - } - else - { - throw; - } - } - - return NoContent(); - } - - // POST: api/Histories - // 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> PostHistory(History history) - { - _context.Edits.Add(history); - await _context.SaveChangesAsync(); - - return CreatedAtAction("GetHistory", new { id = history.Id }, history); - } - - // DELETE: api/Histories/5 - [HttpDelete("{id}")] - public async Task> DeleteHistory(int id) - { - var history = await _context.Edits.FindAsync(id); - if (history == null) - { - return NotFound(); - } - - _context.Edits.Remove(history); - await _context.SaveChangesAsync(); - - return history; - } - - private bool HistoryExists(int id) - { - return _context.Edits.Any(e => e.Id == id); - } - } -} diff --git a/Controllers/ProjectsController.cs b/Controllers/ProjectsController.cs index 1167f67..d8232d9 100644 --- a/Controllers/ProjectsController.cs +++ b/Controllers/ProjectsController.cs @@ -1,16 +1,18 @@ using System.Collections.Generic; using System.Threading.Tasks; +using System.Linq; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using TicketManager.Data; using TicketManager.Models; +using TicketManager.DTO; namespace TicketManager.Controllers { // [Authorize(Roles = "Admin")] - [Authorize] + // [Authorize] [Produces("application/json")] [Route("api/v1/[controller]")] [ApiController] @@ -36,6 +38,7 @@ namespace TicketManager.Controllers [ProducesResponseType(StatusCodes.Status200OK)] public async Task> GetProjects() { + return await _projects.List(); } @@ -53,11 +56,14 @@ namespace TicketManager.Controllers [HttpGet("{id}")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] - public async Task> GetProject(int id) + public async Task> GetProject(int id) { Project project = await _projects.Get(id); - if (project == null) { return NotFound(); } - return project; + if (project == null) + { + return NotFound(); + } + return new ProjectDTO(project); } /// diff --git a/Data/AppDbContext.cs b/Data/AppDbContext.cs index b249c6b..af77479 100644 --- a/Data/AppDbContext.cs +++ b/Data/AppDbContext.cs @@ -12,7 +12,7 @@ namespace TicketManager.Data public DbSet AppUsers { get; set; } public DbSet Tickets { get; set; } public DbSet Assignments { get; set; } - public DbSet Edits { get; set; } + public DbSet Activities { get; set; } public DbSet Notes { get; set; } public DbSet Files { get; set; } diff --git a/Data/AppUserRepository.cs b/Data/AppUserRepository.cs index 66a2cde..a8b4a62 100644 --- a/Data/AppUserRepository.cs +++ b/Data/AppUserRepository.cs @@ -16,7 +16,7 @@ namespace TicketManager.Data .Include(p => p.Assignments) .ThenInclude(a => a.Project) .ThenInclude(p => p.Tickets) - .Include(p => p.Edits); + .Include(p => p.Activities); } public async Task GetUser(Guid id) diff --git a/DataTransfertObjects/ProjectDTO.cs b/DataTransfertObjects/ProjectDTO.cs new file mode 100644 index 0000000..df34f0b --- /dev/null +++ b/DataTransfertObjects/ProjectDTO.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using TicketManager.Models; + +namespace TicketManager.DTO +{ + public class ProjectDTO + { + public ProjectDTO(Project project) + { + Id = project.Id; + Title = project.Title; + Description = project.Description; + CreatedAt = project.CreatedAt; + Progression = project.Progression; + Status = project.Status.ToString(); + Manager = project.Manager; + AppUsers = project.GetMembers(); + Tickets = project.Tickets; + Activities = project.Activities; + Files = project.Files; + } + + public int Id { get; set; } + + public string Title { get; set; } + + public string Description { get; set; } + + public DateTime CreatedAt { get; private set; } = DateTime.Now; + + public DateTime PlannedEnding { get; set; } + + public decimal Progression { get; set; } + + public string Status { get; set; } + + public AppUser Manager { get; set; } + public List AppUsers { get; set; } = new List(); + + public List Tickets { get; set; } = new List(); + + public List Activities { get; set; } = new List(); + + public List Files { get; set; } = new List(); + } +} \ No newline at end of file diff --git a/Models/History.cs b/Models/Activity.cs similarity index 86% rename from Models/History.cs rename to Models/Activity.cs index e039343..dcad951 100644 --- a/Models/History.cs +++ b/Models/Activity.cs @@ -1,9 +1,8 @@ using System; -using System.Collections.Generic; namespace TicketManager.Models { - public class History + public class Activity { public int Id { get; set; } public string Description { get; set; } diff --git a/Models/AppUser.cs b/Models/AppUser.cs index 63f2a4d..41b08c6 100644 --- a/Models/AppUser.cs +++ b/Models/AppUser.cs @@ -42,7 +42,7 @@ namespace TicketManager.Models public List Assignments { get; set; } = new List(); [Display(Name = "Activity")] - public List Edits { get; set; } = new List(); + public List Activities { get; set; } = new List(); // Methods public List GetProjects() diff --git a/Models/Interfaces/ITask.cs b/Models/Interfaces/ITask.cs index 124b8c0..8f83813 100644 --- a/Models/Interfaces/ITask.cs +++ b/Models/Interfaces/ITask.cs @@ -11,18 +11,18 @@ namespace TicketManager.Models string Description { get; set; } DateTime CreatedAt { get; } DateTime PlannedEnding { get; set; } - List Edits { get; set; } + List Activities { get; set; } public virtual void AddLogEntry(string description)//, User user) { - History Edit = new History() + Activity Activity = new Activity() { Description = description, ActivityType = ActivityType.Undefined, // User = user, UpdateDate = DateTime.Now }; - Edits.Add(Edit); + Activities.Add(Activity); } } } diff --git a/Models/Project.cs b/Models/Project.cs index 372cd35..fceedcf 100644 --- a/Models/Project.cs +++ b/Models/Project.cs @@ -26,7 +26,6 @@ namespace TicketManager.Models [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)] public DateTime PlannedEnding { get; set; } - // private decimal _progression; [Display(Name = "Progress")] public decimal Progression { @@ -67,7 +66,7 @@ namespace TicketManager.Models public List Tickets { get; set; } = new List(); - public List Edits { get; set; } = new List(); + public List Activities { get; set; } = new List(); public List Files { get; set; } = new List(); diff --git a/Models/Ticket.cs b/Models/Ticket.cs index 24ec37a..5b28ded 100644 --- a/Models/Ticket.cs +++ b/Models/Ticket.cs @@ -38,7 +38,7 @@ namespace TicketManager.Models // public int ProjectId { get; set; } public List Notes = new List(); - public List Edits = new List(); + public List Activities = new List(); public List Files = new List(); diff --git a/client/src/types/Activity.ts b/client/src/types/Activity.ts new file mode 100644 index 0000000..104c50a --- /dev/null +++ b/client/src/types/Activity.ts @@ -0,0 +1,3 @@ +export interface Activity { + Id: number; +} diff --git a/client/src/types/History.ts b/client/src/types/History.ts deleted file mode 100644 index 9f3fbf3..0000000 --- a/client/src/types/History.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface History { - Id: number; -} diff --git a/client/src/types/Project.ts b/client/src/types/Project.ts index 9b41fcc..6bec951 100644 --- a/client/src/types/Project.ts +++ b/client/src/types/Project.ts @@ -1,12 +1,18 @@ import { Ticket } from "./Ticket"; import { User } from "./User"; +import { Activity } from "./Activity"; export interface Project { id: number; title: string; description: string; - progression: number; - tickets: Ticket[]; - users: User[]; + createdAt: string; plannedEnding: string; + progression: number; + status: string; + manager: User; + users: User[]; + tickets: Ticket[]; + activities: Activity[]; + files: File[]; } From c448a375919968d45941133740181015a750c14b Mon Sep 17 00:00:00 2001 From: Ruidy Nemausat Date: Fri, 21 Feb 2020 14:07:43 +0100 Subject: [PATCH 15/21] projectPage fetch unauthenticated API --- DataTransfertObjects/ProjectDTO.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DataTransfertObjects/ProjectDTO.cs b/DataTransfertObjects/ProjectDTO.cs index df34f0b..ccfa8a3 100644 --- a/DataTransfertObjects/ProjectDTO.cs +++ b/DataTransfertObjects/ProjectDTO.cs @@ -15,7 +15,7 @@ namespace TicketManager.DTO Progression = project.Progression; Status = project.Status.ToString(); Manager = project.Manager; - AppUsers = project.GetMembers(); + Users = project.GetMembers(); Tickets = project.Tickets; Activities = project.Activities; Files = project.Files; @@ -36,7 +36,7 @@ namespace TicketManager.DTO public string Status { get; set; } public AppUser Manager { get; set; } - public List AppUsers { get; set; } = new List(); + public List Users { get; set; } = new List(); public List Tickets { get; set; } = new List(); From 19116dc5f33cfb74e52e799ee41ffcbfa80865de Mon Sep 17 00:00:00 2001 From: Ruidy Nemausat Date: Fri, 21 Feb 2020 18:14:21 +0100 Subject: [PATCH 16/21] Added http type to handle api response and manage errors. created get, post, put method. Added ErrorPage blanck to redirect to --- client/src/{viewModels => VM}/ProjectVM.ts | 0 client/src/{viewModels => VM}/TicketVM.ts | 0 client/src/{viewModels => VM}/UserVM.ts | 0 client/src/controllers/ProjectController.tsx | 119 +------------------ client/src/controllers/TicketController.tsx | 105 ++++++++++++++++ client/src/pages/ErrorPage.tsx | 12 ++ client/src/pages/ProjectPage.tsx | 2 +- client/src/utils/http.ts | 37 ++++++ client/src/utils/router.tsx | 7 +- 9 files changed, 166 insertions(+), 116 deletions(-) rename client/src/{viewModels => VM}/ProjectVM.ts (100%) rename client/src/{viewModels => VM}/TicketVM.ts (100%) rename client/src/{viewModels => VM}/UserVM.ts (100%) create mode 100644 client/src/pages/ErrorPage.tsx create mode 100644 client/src/utils/http.ts diff --git a/client/src/viewModels/ProjectVM.ts b/client/src/VM/ProjectVM.ts similarity index 100% rename from client/src/viewModels/ProjectVM.ts rename to client/src/VM/ProjectVM.ts diff --git a/client/src/viewModels/TicketVM.ts b/client/src/VM/TicketVM.ts similarity index 100% rename from client/src/viewModels/TicketVM.ts rename to client/src/VM/TicketVM.ts diff --git a/client/src/viewModels/UserVM.ts b/client/src/VM/UserVM.ts similarity index 100% rename from client/src/viewModels/UserVM.ts rename to client/src/VM/UserVM.ts diff --git a/client/src/controllers/ProjectController.tsx b/client/src/controllers/ProjectController.tsx index 283d329..ad41468 100644 --- a/client/src/controllers/ProjectController.tsx +++ b/client/src/controllers/ProjectController.tsx @@ -1,13 +1,9 @@ import React, { FC, useState, useEffect } from "react"; import { useParams } from "react-router-dom"; import { ProjectPage } from "../pages/ProjectPage"; -import ProjectVM from "../viewModels/ProjectVM"; +import ProjectVM from "../VM/ProjectVM"; import { Constants } from "../utils/Constants"; import { Project } from "../types/Project"; -// import { Ticket } from "../types/Ticket"; -// import { User } from "../types/User"; -// import { AppFile } from "../types/AppFile"; -// import { Activity } from "../types/Activity"; import { Preloader } from "../components/Preloader"; export const ProjectController: FC = () => { @@ -15,9 +11,9 @@ export const ProjectController: FC = () => { const [isLoading, setIsLoading] = useState(true); const { id } = useParams(); - const getProject: (id: number) => void = (id: number) => { - fetch(`${Constants.getProjectURI}/${id}`) - .then(res => res.json()) + const getProject: (id: string) => void = async (id: string) => { + await fetch(`${Constants.getProjectURI}/${id}`) + .then((res: Response) => res.json()) .catch(err => console.log(err)) .then(data => setProject(data)) .finally(() => setIsLoading(false)); @@ -25,115 +21,10 @@ export const ProjectController: FC = () => { useEffect(() => { if (id !== undefined) { - getProject(parseInt(id)); + getProject(id); } }, [id]); - // const viewModel = new ProjectVM(project); - - // const tickets: Ticket[] = [ - // { - // id: 1, - // title: "Client objective meeting", - // description: "Client objective meeting", - // plannedEnding: "2020-02-17 15:51:02.787373", - // status: "Done" - // }, - // { - // id: 2, - // title: "Assemble Outcomes Report for client", - // description: "Assemble Outcomes Report for client", - // plannedEnding: "2020-02-27 15:51:02.787373", - // status: "To Do" - // } - // ]; - - // const users: User[] = [ - // { - // id: "1", - // firstName: "PacMan", - // picture: - // "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAkGBxIQEBUQERAVFQ8VFhUVFRcVFRUYFRUVFRUXGBUVFxYYHSggGBolHRUVITMhJS0rLi4uFx8zPTMtNygtLisBCgoKDg0OGhAQGi0dHyUtLS0tLS8tLS8tLS0tLS0rLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLf/AABEIAK8ArwMBEQACEQEDEQH/xAAcAAABBAMBAAAAAAAAAAAAAAAAAQIDBAUGBwj/xABJEAACAgEBBAUGCQcLBQEAAAABAgADEQQFEiExBkFRYXEHEyIyQpEUI1JicoGCksEzQ1Njc6KxCBU0RIOTobLC0vBUo7TD0ST/xAAbAQACAwEBAQAAAAAAAAAAAAAAAQIDBAYFB//EADMRAAICAQMCBAQFBAIDAAAAAAABAgMRBAUhEjEGQVFhE3GRsRQigaHRJDJC4UNSFSPw/9oADAMBAAIRAxEAPwDuMACABAAgAQAIAQanUpWpexlRBzLEAe8yMnGKywwY6zbRb8jQ79jN8WnjvMN7HgpmO7cKa1yySgyu9uqfibUrHya694gftLODeO4J5lu8v/jX1LFAhbRsfW1F7f2hUfuATBZu2pbznHyJdCIzs1O20+N9/wDvmWW6ar/sS6EMbZidTWjw1Go/3yv/AMprV/mHQgGldfU1N6/2m8P3wZOO96yHmn8w+GmSLrNXWeFtdo+TahrY93na8gf3Zm+nxHL/AJYfQi6UWaukqr/SKXq7WHxlXjvpxA72UT1tNvGlv4Tw/cqdTRmdLqUtUPW6vW3JkYMp8COBnqrD7ECeMAgAQAIAEACABAAgAQASLIDbbAoyTgAEkngAAMkknkIwMRZtR7eGnACH864OMfq05v4nA6/S5TBqNdCviPLJKLZFXoVDCxibLRydzlhnnu9SfZAni26myecstUcFkrMMlzkYhWUzJCbspaAaVlUiSEKymSGRlZS+AGMsoaQyMrIuTGU30IDm2tmquPEvWcFz1ecXBWz7QJ756Wj3TUUNdMuPRkJVpl3TdIHq9HVgBOq9AfN47bUyTUe/LL15XkOw0G9UanEW8S9zPKto2KtgQCDkHiD2jtnt/IrHQAWABAAgAQAIAETeAK2u1a1JvOevAA4szHkqjrMUpqKyxmLah7yGvACg5WnmqkcjYeVj93qg8s43j5Go1cpcRJRiXMTzmsvJPOAxK5IkJiUNABEpkiQ0rKZAJuyiRJCFZTIYwrKZDQwrKWMjZZVICMrIpjGlZYp+gmslTTec0hzpxvU5y+n5DieJoPKtuvd4Kx4egTvTqNr3x14hc+PUonX6Gy7O2hXfWLK2ypyDzBVh6ysp4qw6weM7KE42JSi8oz4wW8yYCwAIAEAEikBBrdWtSF2z2AAZLMThVA6yScRSkorLAxunoZn89dg2keio4rUp9le/lluvuAxPH1OocnhFiWC4BM3TnkkGJBoAxKZDQmJRIkBlEgGmUyGJM8iSGmUyGhplMhjSJRIYxllMmMYVkMgMZZJMCJlk4gVHR6bDqKONnDzlecLeq8gTyFgHquewKeHL39o3eWmkq58wf7FNleTZ9n65L61trOUbPPgQQSGVh1MCCCOogzvYSU1lMyvgsyYCwAIANdsDPVz4wAwmnfz7+fb1BnzKnlunnafnMM47F7N4zx9ZqHKXSuxNRL4mOLJjxLWwDEpkwEMonwMjZwOZA44Ges9njK5QfkPIEzPNYGhDM8hiTPIkhplMhoa0plzwhjCZVOL7LljGhwRkHI7pVOt9sPIJoJQ+BjSIICNlk0wI2EkmBTTU/A7Tf/V3x8IHUvDC6jHaBgP2qAfYnWbDunTJUWPv2M1sPM29TmdmmUDowCAGH21Z5xhph6pG/d2ebyQEP0yCMfJV5i1t/wAOGPUlFckyzwYybWGWtYJBLExDxG5AEg2BgOm3SRdm6KzVMMsMLWp9u1s7i+HAk9wMs09Ltnhg3hHlrbe3NRrbmv1FrWOT1ngo57qDkqjsE6OuquCwils6L5Hun1tV6aDU2M+nswlTOcmqz2VyfYPLHUSJ5m4aKEoOUUThI7xOTaxwXhKJEkNMpkMY0pfcZwTyt9O7btRZotPYV01ZKWFCR55x64JHNAcjHI4z2Ttdl2quiv4s1mT5M055Zoew9vajRXLdp7WRweIBO6w+Sy8mHjPZ1GmqvrcLIlak0em+iW3k2hpK9UnDeBDr8ixTh1/EdxE+YbloZaO5wfbyfsba5dSMzPOJjGEkIjYSSYENi5BHjLU8NNCccom6MakoW0jfmxvUn5VBOAv0qz6B+b5s9eB9I2nXfiqU5f3LhmOawzYZ6pAjtcKCzEBQCSTyAAySTFnCyBg9nZYG1gQ9p84QeYU4CIe8IBnvJnM6u3rtbLorgvLM6kSJBJdQDodQBE5AcS/lGbQOdJpgTu4suI6iSQi+7DfeM9jaocNlczi09YrH02lGDqcMpDA9hByDBrKwB7E2XqhdRVcOVlaWffQN+M4HUx6bJL3NS7FgzHJkhplMmMobb1fmdNdd111WOPFVJH8JLTQ67oL3QpdmeQ3csSxOSTk+J5z6clgxjY88Ado/k+a4ldVpzyBrtHcSCp/gPdON8WVflrn80aKDsE4o0iERiGMI0BCwk0BQ17morqVGWpO+wHNqsYuXHWdzJA+Uqz29k1ap1KUuz4KrY5RuFbAgEEEHiCORB5ET6J3RkMZ0ifNa0/pXCH6ABeweBVWH1zNrLVXS2yUVyIpnJ9T7svwSrJKQYHiPqELmPIBmRbA4X/KK05+EaW32TXYg8UcE/wCcToNompVsrmjj89ZFYuImB6/2BpjTpNPSeddFSHxStVP8JwOsn1XSfua49i8ZhkMaZTJjMX0o05t0WprHN6LVH1oZdobOnUQfuhSXDPJGJ9OX5jGJEgOwfyfNMd/V2+zu1JnvJY/hOR8VyXwq4+7ZooR2icMaQgIawjAiYSaAhcSyDxyBb6J3fEGk+tQ7Un6KgNV/23rP1z6ht1/x9PCfngwzWGM2g2/qwOqqnPi17ke8LQ395MO829KUPUnBE6mc71FpKsl1APEakLAuZLqATMi5AaX5V+jDbR0DLUM6ipvO1DHFiAQ9Y+kpPDtVZ6G3alVW89mRmso8yPWQSDwYEgggggjmD3zq8p8ooNw8l3RV9frkJX/81LCy5urCnKp3liOXZk9Uw7hqo0Uteb7E4Ryz02JwcnyaQlTYxplMmMY0q6nFpruGDzF5R+i7bP1rqFPwewl6WxwKk8Uz2qeHgAeufSdr1sNVp1LP5lwzJOOGatXWWIVQSScAAcSTyAE9FyUV1S8iGD0z5MujZ2doErsGNRYTbb2hmA3Uz81QB45nzTfdctXqXKP9q4RsqjhG2TxC0IABEAInEmhELiTTAbsRtzWWL7NtKt9ulyrHxK21DwrE7nw3c5aeUPRmW5cj62zqNQ36xV+5Un4k++V73Nu9J+SHX2LamePkmSpH1APj6gDMOoAh1AIRI5GaztvoFs7WW+ev0qm0+sys6F/p7hG8e88e+bIbnqK49MZcfoRcEzMbK2VRpahTp6lrqXkqjr7SebHvOTMWo1E7pdU3lklFLsWxMspEglTYDZU2SGtKnJp5Q0Udr7Ko1dZp1FS2VnjhhyPaCOKnvGDJUau7Ty6qpYZFxT7mI2L0G2fo7PO0aVRaOTsXdl+jvk7p7xxmy/etZfDpnPK/RfYSrijY8TyctlgsQBAAgAx5JCIWli7AVK33NXp27TanvrLf+udR4ascbZL2KLkTaT17/wBvZ/pH4Sze5f1OPZBWuC6hnldRMmSHUA+PqAMw6gDMOoBIuoBDIOQCZlbY8BmQbGNlTYCSpsYhlTYxJAAiGEACPABAAiAY0khELyaAoazhbpz2XH/x750Xh1/1OPZlNpY0p+MvH69/8Qp/Gad8X9Z+iCvsXkM8fqJEqmHUMfmHUAhaHUAb0Ov1AMyPUAZkXIBCZByGJIOQxJU2AkrbGJK2ARDCABGgEJkll8CyKDIvuMIgGPJIRC8mgKGq43acdtrf4ae+dF4dX9Q37FNvYsuN3V6heWTVYPB69zP3qX903eII9N8Zeq+wqeUWkM5vqLMEqGPqHgfmJTXmBHqtQtaNZYwWtAWZjyVQMkn6pbVXOyaUVnIma15P9pajV6ezV3k+buusbTIVUFNODuoOA7jPS3SFVM40wXKX5vmRjlm05nj9RPASDYYEJkWx4DMg5DElbYCSGRhEAQAIABjQmat0+2lqNHVTq6mPmKr0+FKADvUOd1uY4Yz1dvdPc2amm+U6592vy/MhY2uTZaLldVdCCjAMpHIgjIInkXUyqm4y4aJoklaQyNzBCIWMmgK+mXe1tAxkKtznu9FUB/fnWeGKuqycn6IoufkT7eTc1VVnVaj0sfnIRZT+6dR94T0/EdKdMbP+r+5Cl8jkacO+DQTKYJtvCA1nWeUbZlX9bV244WpXsYkdQ3RjPiRPVr2bVWc9HT7vj7kHYjRulXSuzW6nTaXV026PZN7gkv6Nt6g4G/8AITJGR2HOTwnvaLb4aaudlUlOxL9EVSnlpHYKalRQiqFRQFVQMBVUYUAdWBOOuslKTcnzk0pcEkqcgDMi5DEkHIBMyOQCIAiGEACABAAMaAh1VK2I1dihq2BVg3IqR6QPdiX0ucZqUeGvuRfKOR9EOl1uku1On09F2r2Tp3O4yjetpQk8vlpwbAPIDqnaa/bK9TCNs2q7Wv0bM8JtduxvOj8oWzLcAaxUckDdsV62B+Sd8ATnbtk1lfPR1e65LlbE2R55BMhaWQWXgA6Ppv6m+32a1roH0zm23916B4qZ3vhunp0zs9WZLnyXelGnL6csilrKiLlA5sazllAHWV3h9c9bW6f49EqyuDwzH02BgGUgqQGBHIqRkEdxE+YWxlGTi+64NyeSwhlfVgCLT6ClDvJTWrc8qig58QJY9Va1hyf1YYRr/lL6MfzlomRFB1FebKe0sB6SZ+cOHjiensm4/htRiT/LLhkLIZRgvJL01+FVfAdQ2NZSN1d7g1ta8Ov214AjmRx4+kRv37bHXP8AEVf2vv7f6ZCqf+LOkAzlngvCRbxwMJEAgAQAIAEACABABG5SUe4HNPK30zNCHZ2mYnV3AK5X1q0f2R89xw7QDngSDOs2HbOuX4m1Ygu3v7/JGeyfkjY/J10Y/m3QpUR8e/xlx+eR6vgowPHJ655e87h+K1LcX+VcInXDpRnb9n0s281NbN2lFJ95E82OotSwpPHzZPCJXaVpDK99oRWdjhVBYnsABJPuGZdVW5zUV5ibwjJ9GtKa9Mu+MWWFrXHWGsJYg+GQPqn1PSUqimMF5GGXLMoRNCEahRT5i2zTcgh36v2LklQO5GDJ3AL2jPBb9onVf1pcS+5pqlxguqZzrReSoZBgPiTwByLyq9DLKbf520G8titv3BPWVhx8+v8Aq9/bO12Lc43V/hb+fJZ816fwZ7INPqRn/J55RqtoKtGoK160ADHAJdjrTsbtX3d3n7vsc6P/AGUrMft8ycLE+Df5zTRaLFgAhgYQAIgCMAhhgJmNxFk575RPKRXoVbT6Vls1p4E80p72PIv8339h6faNhne1ZcsQ/dlNluOEYbyUdC7Gs/nbXAm1iXpV87xLc7mB6+Po58eya993SFcPwlHC88fb+SNcG31M63OMfJoI2MaQETGWRWQKdlPn7q9PzUkW3fsq2BCEdjuFXHWA4nSeHtH8S74klwvuUWy4NuWd35cmUdGMwnSbQs6rdUub6csoGM2I2POVcetgARnhvKkwbho46qmVb7+RKMsMx+l1C2ItiNvIwDKRnBB8eI8DxE+a3VSrk4SWMGxPJZVpmaJEimRAdjMlGcovMeBvk5D5QvJYSzavZq4bO89A4ceZak9X0fd2Ts9p8QxaVWp+v8madWOYmF6KeVbVaM/B9cjXVp6OT6N9eOGDn18fO4982a7w/Rql8Sl9Lf0ZGNrXDOt7A6ZaHXAeY1KFz+bc7lg+w3PxGROR1e0arTP80Hj1XKL42JmennOMkTyLIMAgAhk1GTDODX+kHTTQ6EHz+pXzg/Nod+w/ZX1fFsDvnp6XaNXqXxFper4RB2JHJelXlS1euPwbQ1tTW53fRG9fZnqBA9HwXj3zrdBsOn0q+Jc1Jr6L/wC9yiVrlwjP+TzyWebZdXtFQbPWSg8QDzDWn2j17vLt7J5+7eII4dWm+v8ABKFPmzrc46UnJ5Zo7DHaISImMkhlfV6ha0axzhVBJ8PDrJ5YHE8ppoqlbNQiuWRk8IyXRvQNWhttGNRaQzjgdxQMV1A9iqfvM5659M0GkjpaVWv1+ZjlLLMwJtIiwAQiLIGqbV03wS02j+i2Nl+yi1jxf9m5Iz8luPJju83vm1/FXxa1z5+5dXZgmU/8/jOGa5NS5JFaQawBKDIAKIZYGvdKehOi2iPj6sW8hbX6Ng8TyYdzAz1NBu+p0rxGWY+j7EJQUjk+3vI5rKSW0jrenMAkV2j6mO6ffOu0viTTW8Wrpf7FEqmuxghtHbWzjul9XSByDhyh8N8FSPCb/g7fq1n8svl3/bkhmcSzV5WNrLz1Ct9Kmof5VEpl4e0Eu0Mfqx/FkFvlX2s3BdQqn5tNR/zKYR8P7fHlxz82/wDQfFkVTr9tbR9ENrLgTyUOE49u6AoH+EuVWg0vOIx+/wDIZnI2DYPkb1dpDauxaE61BFlp9x3R7zPO1XiXTV5jSnJ/RElU33Or9Fuhuj2cvxFWbcYNr+lYfteyO5cCcnrt11OrbU5YXou3+y+MFE2EzyiYwtGGCMtJpARsZNReceYEWyNL8KtW9v6LW2av1tqn8r31r7PafS5BSe52Ta1TH41i/N9jLbZnhG0qJ0pSOgAQASADLawylWAKkEEEAggjiCDzEWMgalqdM2hIVsnRkgV2Hiac8BVafkcgrnlwVuonkd62XL+NQvmv4L67PUtg/wDPwxOQlFrhmhPJIrSDQx4aRwA8NEAohxgYd3VJKUo9mLgq2bMob1qKie+tT+Etjq7l/m/qxdKCvZlC+rRUPCtB+EJau595v6sOlFodnVKZTk/MfARDELQwIYWjwBGWksAMYycVl8dwKmk0x1xwCRohwdxwN+OddZ5iv5T+1yHAkzsdn2ZxavvXyRnst9Dba6woCqAFAAAAwAByAE6tccmcfH5gLGAQAIAEAI7UDKVIBBGCCMgg8wQeYixnuDNY1myrNLxpVrdN+iHG2odlX6ROys8R1ZGFHO7pscbs2VcS9PUthZgTS6pLFDowZeWR2jmCOYYciDgg8wJxNtNlM3Caw/c0xkmThpQ0SHhpHADg0WAHb0WADehgA3oYAN+GAG70eAGl48AMLSSQEGp1SVrvOwC8h1kk8AqqOLMTwAGSTNFOnndJQrWWQlJIdo9kWan0tQpr0/VST6dvZ54j1U/Vjn7RxlZ2u2bJGhKy5Zl9iiy3PCNmRAAAAAAMADkAOoToksFKJIwCABAAgAQAIAJABCuYsAYraWwa7WNqsatR+kTGW7rFI3bF6vSGR1EHjMuq0dWpj02LPuSUmjD3LfR+WpLIPzlAZx4tUM2L9W9jt65yWr8OWxzKp5XoXxu9R+m1aWLvVurr2qQR4cOU52yidbxNNP3Lk0yYNKWhjt6GEAb0WADehgALR4QCFo1BsCDVauuob1jqg7WIHHs48z3c5dVprbXiEW/kJySG0JqL/wAlVuJ+kvVl+sU8LD9rc93GdFpPDlkmna+n2KZXehmNmbDrqbzjMbdR+ksxvDPMIoAWterCjxJPGdZpdFTpo9NUcFEpNmVAmsgEQxYwCABAAgAQAIAEACABABuJHuBj9dsSi47z1Dzny1yln31w0qt09dixNJjUmjHWdHrF/JatwPk3oty/eXcsP1uZ5d+xaOznpx8iatkiFtnaxfZofwexCfssrY+8Z5tnhiD/ALJ/sTVz8xo0+r/6UfVcn+2Z34Ys8pIfxhPg+s6tKPrvT/4YR8MWecg+MPGztYfZ06fSeyzH2VVc++aIeF4f5zYnd6E9fR52Px2rcjPq0qtKEdmfSsH1OJ6VOwaSvuur5kHbJmR0GxqKTvV1Df8Altln7/TbLT1a6K6o4hHBDqbL+7LcpiHARgEACABAAgAQA//Z" - // }, - // { - // id: "2", - // firstName: "Avatar", - // picture: - // "data:image/png;base64,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" - // }, - // { - // id: "3", - // firstName: "Zoey", - // picture: - // "data:image/jpeg;base64,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" - // }, - // { - // id: "4", - // firstName: "Kory", - // picture: - // "data:image/jpeg;base64,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" - // } - // ]; - - // const files: AppFile[] = [ - // { - // id: 1, - // name: "SRS", - // description: "App blueprint", - // size: 15, - // format: "pdf" - // }, - // { - // id: 2, - // name: "Business Model Canvas", - // description: "Path to 1B$", - // size: 2100, - // format: "png" - // } - // ]; - - // const activities: Activity[] = [ - // { - // id: 1, - // description: " completed the task ", - // date: new Date(), - // user: users[0], - // ticket: tickets[0] - // }, - // { - // id: 2, - // description: " added the task ", - // date: new Date(), - // user: users[1], - // ticket: tickets[1] - // }, - // { - // id: 3, - // description: " rescheduled the task ", - // date: new Date(), - // user: users[2], - // ticket: tickets[1] - // }, - // { - // id: 4, - // description: " added the task ", - // date: new Date(), - // user: users[3], - // ticket: tickets[0] - // } - // ]; - // const project: Project = { - // id: 1, - // title: "Project Title", - // description: "What is it about", - // progression: 25, - // tickets: tickets, - // users: users, - // plannedEnding: "2020-02-17 15:51:02.787373", - // files: files, - // activities: activities - // }; - const viewModel = new ProjectVM(project); return isLoading ? : ; diff --git a/client/src/controllers/TicketController.tsx b/client/src/controllers/TicketController.tsx index afc218e..5d3a949 100644 --- a/client/src/controllers/TicketController.tsx +++ b/client/src/controllers/TicketController.tsx @@ -4,3 +4,108 @@ import { TicketPage } from "../pages/TicketPage"; export const TicketController: FC = () => { return ; }; + +// const viewModel = new ProjectVM(project); + +// const tickets: Ticket[] = [ +// { +// id: 1, +// title: "Client objective meeting", +// description: "Client objective meeting", +// plannedEnding: "2020-02-17 15:51:02.787373", +// status: "Done" +// }, +// { +// id: 2, +// title: "Assemble Outcomes Report for client", +// description: "Assemble Outcomes Report for client", +// plannedEnding: "2020-02-27 15:51:02.787373", +// status: "To Do" +// } +// ]; + +// const users: User[] = [ +// { +// id: "1", +// firstName: "PacMan", +// picture: +// "data:image/jpeg;base64,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" +// }, +// { +// id: "2", +// firstName: "Avatar", +// picture: +// "data:image/png;base64,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" +// }, +// { +// id: "3", +// firstName: "Zoey", +// picture: +// "data:image/jpeg;base64,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" +// }, +// { +// id: "4", +// firstName: "Kory", +// picture: +// "data:image/jpeg;base64,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" +// } +// ]; + +// const files: AppFile[] = [ +// { +// id: 1, +// name: "SRS", +// description: "App blueprint", +// size: 15, +// format: "pdf" +// }, +// { +// id: 2, +// name: "Business Model Canvas", +// description: "Path to 1B$", +// size: 2100, +// format: "png" +// } +// ]; + +// const activities: Activity[] = [ +// { +// id: 1, +// description: " completed the task ", +// date: new Date(), +// user: users[0], +// ticket: tickets[0] +// }, +// { +// id: 2, +// description: " added the task ", +// date: new Date(), +// user: users[1], +// ticket: tickets[1] +// }, +// { +// id: 3, +// description: " rescheduled the task ", +// date: new Date(), +// user: users[2], +// ticket: tickets[1] +// }, +// { +// id: 4, +// description: " added the task ", +// date: new Date(), +// user: users[3], +// ticket: tickets[0] +// } +// ]; +// const project: Project = { +// id: 1, +// title: "Project Title", +// description: "What is it about", +// progression: 25, +// tickets: tickets, +// users: users, +// plannedEnding: "2020-02-17 15:51:02.787373", +// files: files, +// activities: activities +// }; diff --git a/client/src/pages/ErrorPage.tsx b/client/src/pages/ErrorPage.tsx new file mode 100644 index 0000000..01326e2 --- /dev/null +++ b/client/src/pages/ErrorPage.tsx @@ -0,0 +1,12 @@ +import React, { FC } from "react"; + +interface IProps { + error: any; +} +export const ErrorPage: FC = ({ error }) => { + return ( +
        +

        {error}

        +
        + ); +}; diff --git a/client/src/pages/ProjectPage.tsx b/client/src/pages/ProjectPage.tsx index 8c49f6b..7e79034 100644 --- a/client/src/pages/ProjectPage.tsx +++ b/client/src/pages/ProjectPage.tsx @@ -2,7 +2,7 @@ import React, { FC } from "react"; import { Header } from "../components/Header"; import { AvatarList } from "../components/AvatarList"; import { ProgressBar } from "../components/ProgressBar"; -import ProjectVM from "../viewModels/ProjectVM"; +import ProjectVM from "../VM/ProjectVM"; import { TabRouter } from "../components/TabRouter"; import { FloatingButton } from "../components/FloatingButton"; diff --git a/client/src/utils/http.ts b/client/src/utils/http.ts new file mode 100644 index 0000000..9f9acf6 --- /dev/null +++ b/client/src/utils/http.ts @@ -0,0 +1,37 @@ +export interface HttpResponse extends Response { + parsedBody?: T; +} + +export async function http(request: RequestInfo): Promise> { + const response: HttpResponse = await fetch(request); + try { + response.parsedBody = await response.json(); + } catch (ex) {} + if (!response.ok) { + throw new Error(response.statusText); + } + return response; +} + +export async function get( + path: string, + args: RequestInit = { method: "get" } +): Promise> { + return await http(new Request(path, args)); +} + +export async function post( + path: string, + body: any, + args: RequestInit = { method: "post", body: JSON.stringify(body) } +): Promise> { + return await http(new Request(path, args)); +} + +export async function put( + path: string, + body: any, + args: RequestInit = { method: "put", body: JSON.stringify(body) } +): Promise> { + return await http(new Request(path, args)); +} diff --git a/client/src/utils/router.tsx b/client/src/utils/router.tsx index 7f8078e..56f8752 100644 --- a/client/src/utils/router.tsx +++ b/client/src/utils/router.tsx @@ -2,7 +2,8 @@ import React from "react"; import { Router, Route, - Switch + Switch, + Redirect //Link, NavLink } from "react-router-dom"; import * as creacteHistory from "history"; @@ -31,6 +32,10 @@ export const AppRouter = () => { {/* */} + + + +
      From 202eaad2df2358f15e0fec26fad6ae5500a735ce Mon Sep 17 00:00:00 2001 From: Ruidy Nemausat Date: Fri, 21 Feb 2020 20:53:51 +0100 Subject: [PATCH 17/21] redirect to error page if project get unsuccessful --- client/src/controllers/ProjectController.tsx | 31 +++++++++++++------- client/src/utils/http.ts | 2 ++ client/src/utils/router.tsx | 7 ++++- 3 files changed, 29 insertions(+), 11 deletions(-) diff --git a/client/src/controllers/ProjectController.tsx b/client/src/controllers/ProjectController.tsx index ad41468..472a15a 100644 --- a/client/src/controllers/ProjectController.tsx +++ b/client/src/controllers/ProjectController.tsx @@ -1,31 +1,42 @@ import React, { FC, useState, useEffect } from "react"; -import { useParams } from "react-router-dom"; +import { useParams, Redirect } from "react-router-dom"; import { ProjectPage } from "../pages/ProjectPage"; import ProjectVM from "../VM/ProjectVM"; -import { Constants } from "../utils/Constants"; import { Project } from "../types/Project"; import { Preloader } from "../components/Preloader"; +import { Constants } from "../utils/Constants"; +import { HttpResponse, get } from "../utils/http"; export const ProjectController: FC = () => { const [project, setProject] = useState({} as Project); const [isLoading, setIsLoading] = useState(true); + const [hasError, setHasError] = useState(false); const { id } = useParams(); - const getProject: (id: string) => void = async (id: string) => { - await fetch(`${Constants.getProjectURI}/${id}`) - .then((res: Response) => res.json()) - .catch(err => console.log(err)) - .then(data => setProject(data)) - .finally(() => setIsLoading(false)); - }; + async function httpGet(id: string): Promise { + try { + const response: HttpResponse = await get( + `${Constants.getProjectURI}/${id}` + ); + if (response.parsedBody !== undefined) { + setProject(response.parsedBody); + setIsLoading(false); + } + } catch (ex) { + setHasError(true); + } + } useEffect(() => { if (id !== undefined) { - getProject(id); + httpGet(id); } }, [id]); const viewModel = new ProjectVM(project); + if (hasError) { + return ; + } return isLoading ? : ; }; diff --git a/client/src/utils/http.ts b/client/src/utils/http.ts index 9f9acf6..ceb53bc 100644 --- a/client/src/utils/http.ts +++ b/client/src/utils/http.ts @@ -1,3 +1,5 @@ +import { Redirect } from "react-router-dom"; + export interface HttpResponse extends Response { parsedBody?: T; } diff --git a/client/src/utils/router.tsx b/client/src/utils/router.tsx index 56f8752..0031748 100644 --- a/client/src/utils/router.tsx +++ b/client/src/utils/router.tsx @@ -10,6 +10,7 @@ import * as creacteHistory from "history"; // import { TicketPage } from "../pages/TicketPage"; // import { HomeController } from "../controllers/HomeController"; import { ProjectController } from "../controllers/ProjectController"; +import { ErrorPage } from "../pages/ErrorPage"; // import { UserController } from "../controllers/UserController"; // import { TicketController } from "../controllers/TicketController"; @@ -33,8 +34,12 @@ export const AppRouter = () => { */} + + + + - +
      From 8f7e790c70661a380f4f099caac5b482e0476bdc Mon Sep 17 00:00:00 2001 From: Ruidy Nemausat Date: Sun, 23 Feb 2020 00:15:02 +0100 Subject: [PATCH 18/21] error handling after get request & redirect to error page --- client/src/controllers/ErrorController.tsx | 11 +++++++++++ client/src/controllers/ProjectController.tsx | 15 +++++++++------ client/src/pages/ErrorPage.tsx | 12 ------------ client/src/pages/NotFoundPage.tsx | 10 ++++++++++ client/src/types/HttpResponse.ts | 3 +++ client/src/utils/http.ts | 8 ++------ client/src/utils/router.tsx | 16 ++++++++-------- 7 files changed, 43 insertions(+), 32 deletions(-) create mode 100644 client/src/controllers/ErrorController.tsx delete mode 100644 client/src/pages/ErrorPage.tsx create mode 100644 client/src/pages/NotFoundPage.tsx create mode 100644 client/src/types/HttpResponse.ts diff --git a/client/src/controllers/ErrorController.tsx b/client/src/controllers/ErrorController.tsx new file mode 100644 index 0000000..e36007a --- /dev/null +++ b/client/src/controllers/ErrorController.tsx @@ -0,0 +1,11 @@ +import React, { FC } from "react"; +import { Redirect } from "react-router-dom"; + +interface IProps { + error: any; +} + +export const ErrorController: FC = ({ error }) => { + if (error === "Not Found") return ; + return <>; +}; diff --git a/client/src/controllers/ProjectController.tsx b/client/src/controllers/ProjectController.tsx index 472a15a..d9c368e 100644 --- a/client/src/controllers/ProjectController.tsx +++ b/client/src/controllers/ProjectController.tsx @@ -1,16 +1,19 @@ import React, { FC, useState, useEffect } from "react"; -import { useParams, Redirect } from "react-router-dom"; +import { useParams } from "react-router-dom"; +import { ErrorController } from "./ErrorController"; import { ProjectPage } from "../pages/ProjectPage"; import ProjectVM from "../VM/ProjectVM"; import { Project } from "../types/Project"; +import { HttpResponse } from "../types/HttpResponse"; import { Preloader } from "../components/Preloader"; import { Constants } from "../utils/Constants"; -import { HttpResponse, get } from "../utils/http"; +import { get } from "../utils/http"; export const ProjectController: FC = () => { - const [project, setProject] = useState({} as Project); + const [project, setProject] = useState({} as Project); const [isLoading, setIsLoading] = useState(true); const [hasError, setHasError] = useState(false); + const [error, setError] = useState(); const { id } = useParams(); async function httpGet(id: string): Promise { @@ -24,6 +27,7 @@ export const ProjectController: FC = () => { } } catch (ex) { setHasError(true); + setError(ex); } } @@ -33,10 +37,9 @@ export const ProjectController: FC = () => { } }, [id]); - const viewModel = new ProjectVM(project); - if (hasError) { - return ; + return ; } + const viewModel = new ProjectVM(project); return isLoading ? : ; }; diff --git a/client/src/pages/ErrorPage.tsx b/client/src/pages/ErrorPage.tsx deleted file mode 100644 index 01326e2..0000000 --- a/client/src/pages/ErrorPage.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import React, { FC } from "react"; - -interface IProps { - error: any; -} -export const ErrorPage: FC = ({ error }) => { - return ( -
      -

      {error}

      -
      - ); -}; diff --git a/client/src/pages/NotFoundPage.tsx b/client/src/pages/NotFoundPage.tsx new file mode 100644 index 0000000..a13397c --- /dev/null +++ b/client/src/pages/NotFoundPage.tsx @@ -0,0 +1,10 @@ +import React, { FC } from "react"; + +interface IProps {} +export const NotFoundPage: FC = () => { + return ( +
      +

      error

      +
      + ); +}; diff --git a/client/src/types/HttpResponse.ts b/client/src/types/HttpResponse.ts new file mode 100644 index 0000000..a5825c0 --- /dev/null +++ b/client/src/types/HttpResponse.ts @@ -0,0 +1,3 @@ +export interface HttpResponse extends Response { + parsedBody?: T; +} diff --git a/client/src/utils/http.ts b/client/src/utils/http.ts index ceb53bc..2ba9a2d 100644 --- a/client/src/utils/http.ts +++ b/client/src/utils/http.ts @@ -1,8 +1,4 @@ -import { Redirect } from "react-router-dom"; - -export interface HttpResponse extends Response { - parsedBody?: T; -} +import { HttpResponse } from "../types/HttpResponse"; export async function http(request: RequestInfo): Promise> { const response: HttpResponse = await fetch(request); @@ -10,7 +6,7 @@ export async function http(request: RequestInfo): Promise> { response.parsedBody = await response.json(); } catch (ex) {} if (!response.ok) { - throw new Error(response.statusText); + throw response.statusText; } return response; } diff --git a/client/src/utils/router.tsx b/client/src/utils/router.tsx index 0031748..5d5f15a 100644 --- a/client/src/utils/router.tsx +++ b/client/src/utils/router.tsx @@ -2,15 +2,15 @@ import React from "react"; import { Router, Route, - Switch, - Redirect + Switch + // Redirect //Link, NavLink } from "react-router-dom"; import * as creacteHistory from "history"; // import { TicketPage } from "../pages/TicketPage"; // import { HomeController } from "../controllers/HomeController"; import { ProjectController } from "../controllers/ProjectController"; -import { ErrorPage } from "../pages/ErrorPage"; +import { NotFoundPage } from "../pages/NotFoundPage"; // import { UserController } from "../controllers/UserController"; // import { TicketController } from "../controllers/TicketController"; @@ -34,13 +34,13 @@ export const AppRouter = () => { */} - - + + - - - + {/* + + */}
    From 6cf52b256bb94e6682db944445c85b8e428ff3fd Mon Sep 17 00:00:00 2001 From: Ruidy Nemausat Date: Sun, 23 Feb 2020 00:56:02 +0100 Subject: [PATCH 19/21] modal component added --- client/src/components/Button.tsx | 6 ++-- client/src/components/FloatingButton.tsx | 8 ++++-- client/src/components/Modal.tsx | 17 +++++++++++ client/src/components/TicketList.tsx | 30 ++++++-------------- client/src/controllers/ProjectController.tsx | 2 +- client/src/pages/ProjectPage.tsx | 2 ++ client/src/utils/Constants.ts | 4 ++- 7 files changed, 40 insertions(+), 29 deletions(-) create mode 100644 client/src/components/Modal.tsx diff --git a/client/src/components/Button.tsx b/client/src/components/Button.tsx index 8fc9f86..bb3c49b 100644 --- a/client/src/components/Button.tsx +++ b/client/src/components/Button.tsx @@ -1,4 +1,4 @@ -import React, { FC } from "react"; +import React, { FC, MouseEvent } from "react"; interface IProps { icon?: string; @@ -6,18 +6,20 @@ interface IProps { shape?: string; color?: string; text?: string; + onClick?: (e: MouseEvent) => void; } export const Button: FC = ({ size = "small", shape = "", color, - text, + onClick, children }) => { return ( diff --git a/client/src/components/FloatingButton.tsx b/client/src/components/FloatingButton.tsx index eb9dfd1..0031443 100644 --- a/client/src/components/FloatingButton.tsx +++ b/client/src/components/FloatingButton.tsx @@ -1,20 +1,22 @@ -import React, { FC } from "react"; +import React, { FC, MouseEvent } from "react"; import { Button } from "./Button"; interface IProps { icon?: string; size?: string; color?: string; + onClick?: (e: MouseEvent) => void; } export const FloatingButton: FC = ({ icon = "add", size = "small", - color = "red" + color = "red", + onClick }) => { const iconComponent = {icon}; return ( - ); diff --git a/client/src/components/Modal.tsx b/client/src/components/Modal.tsx new file mode 100644 index 0000000..714f860 --- /dev/null +++ b/client/src/components/Modal.tsx @@ -0,0 +1,17 @@ +import React, { FC } from "react"; + +export const Modal: FC = () => { + return ( +
    +
    +

    Modal Header

    +

    A bunch of text

    +
    + +
    + ); +}; diff --git a/client/src/components/TicketList.tsx b/client/src/components/TicketList.tsx index 5864041..d1be3c3 100644 --- a/client/src/components/TicketList.tsx +++ b/client/src/components/TicketList.tsx @@ -15,38 +15,24 @@ export const TicketList: FC = ({ tickets }) => { }; const archiveTicket = () => {}; const validateTicket = () => {}; - + const onClick: (e: MouseEvent) => void = (e: MouseEvent) => { + e.preventDefault(); + }; const handleChange: (e: ChangeEvent) => void = ( e: ChangeEvent ) => { setFilterText(e.target.value); }; - // const useFilter = (init: string) => { - // const [filterText, setFilterText] = useState(init); - // // const handleChange: (e: ChangeEvent) => void = ( - // // e: ChangeEvent - // // ) => { - // // setFilterText(e.target.value); - // // }; - // return { - // filterText, - // setFilterText, - // bind: { - // filterText, - // handleChange: (e: ChangeEvent) => { - // setFilterText(e.target.value); - // } - // } - // }; - // }; - // const [filterText, handleChange] = useFilter(""); - // const [filterText, handleChange] = useFilter(""); return ( <>

    Tickets

    - + { async function httpGet(id: string): Promise { try { const response: HttpResponse = await get( - `${Constants.getProjectURI}/${id}` + `${Constants.projectsURI}/${id}` ); if (response.parsedBody !== undefined) { setProject(response.parsedBody); diff --git a/client/src/pages/ProjectPage.tsx b/client/src/pages/ProjectPage.tsx index 7e79034..f0f03fd 100644 --- a/client/src/pages/ProjectPage.tsx +++ b/client/src/pages/ProjectPage.tsx @@ -5,6 +5,7 @@ import { ProgressBar } from "../components/ProgressBar"; import ProjectVM from "../VM/ProjectVM"; import { TabRouter } from "../components/TabRouter"; import { FloatingButton } from "../components/FloatingButton"; +import { Modal } from "../components/Modal"; interface IProps { viewModel: ProjectVM; @@ -23,6 +24,7 @@ export const ProjectPage: FC = ({ viewModel }) => { activities } = viewModel; const tabNames: string[] = ["Tickets", "Files", "Activity"]; + return (
    diff --git a/client/src/utils/Constants.ts b/client/src/utils/Constants.ts index e714aa1..cdfb2b9 100644 --- a/client/src/utils/Constants.ts +++ b/client/src/utils/Constants.ts @@ -1,3 +1,5 @@ export class Constants { - static getProjectURI: string = "/api/v1/projects"; + static projectsURI: string = "/api/v1/projects"; + static ticketsURI: string = "/api/v1/tickets"; + static usersURI: string = "/api/v1/users"; } From d6d46f2850d3497f25fd37dea3fcaa607eb890c1 Mon Sep 17 00:00:00 2001 From: Ruidy Nemausat Date: Sun, 23 Feb 2020 22:06:18 +0100 Subject: [PATCH 20/21] added manage user layout to project page --- .gitignore | 1 + README.md | 25 +++++----- client/src/components/FilterBar.tsx | 2 +- client/src/components/Modal.tsx | 31 +++++++----- client/src/components/UsersModal.tsx | 73 ++++++++++++++++++++++++++++ client/src/pages/ProjectPage.tsx | 21 ++++++-- client/src/utils/router.tsx | 5 ++ 7 files changed, 129 insertions(+), 29 deletions(-) create mode 100644 client/src/components/UsersModal.tsx diff --git a/.gitignore b/.gitignore index 38ee8ff..01d8a9f 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,5 @@ app.db* .DS_Store app.db client/node_modules +client/src/pages/TestPage.tsx Scripts/ diff --git a/README.md b/README.md index 817f04a..01870bc 100644 --- a/README.md +++ b/README.md @@ -33,15 +33,16 @@ ## TO DO -- Write API tests using Postman: request + test, environment variables, mock server -- Annotate API request in controllers -- Annotate Properties in Models -- Write backend tests -- Have a Look at typeahead component -- Ensure Tickets Edits belong to Project Edits -- Ensure Tickets Files belong to Project Files -- Async model methods ? -- update assignments automatically from context -- use PATCH instead of PUT -- logging -- check useRef, useReducer, dispatch +- [ ] Write API tests using Postman: request + test, environment variables, mock server +- [ ] Annotate API request in controllers +- [ ] Annotate Properties in Models +- [ ] Write backend tests +- [ ] Have a Look at typeahead component +- [ ] Ensure Tickets Edits belong to Project Edits +- [ ] Ensure Tickets Files belong to Project Files +- [ ] Async model methods ? +- [ ] update assignments automatically from context +- [ ] use PATCH instead of PUT +- [ ] logging +- [ ] check useRef, useReducer, dispatch +- [ ] error page redirect when offline. diff --git a/client/src/components/FilterBar.tsx b/client/src/components/FilterBar.tsx index a99b24e..fc9cb9c 100644 --- a/client/src/components/FilterBar.tsx +++ b/client/src/components/FilterBar.tsx @@ -13,7 +13,7 @@ export const FilterBar: FC = ({ clearFilterText }) => { const { url } = useRouteMatch(); - const placeholder: string = url.split("/")[3]; + const placeholder: string = url.split("/")[3] || "users"; return ( <>
    diff --git a/client/src/components/Modal.tsx b/client/src/components/Modal.tsx index 714f860..d826e40 100644 --- a/client/src/components/Modal.tsx +++ b/client/src/components/Modal.tsx @@ -1,17 +1,24 @@ -import React, { FC } from "react"; +import React, { FC, useState, CSSProperties } from "react"; -export const Modal: FC = () => { +interface IProps { + handleClose: () => void; + show: boolean; +} +export const Modal: FC = ({ handleClose, show, children }) => { + const showHideStyle: CSSProperties = show + ? { display: "block", zIndex: 10 } + : { display: "none", zIndex: 10 }; return ( -
    -
    -

    Modal Header

    -

    A bunch of text

    -
    - +
    +
    {children}
    + {/*
    + +
    */}
    ); }; diff --git a/client/src/components/UsersModal.tsx b/client/src/components/UsersModal.tsx new file mode 100644 index 0000000..24ab07a --- /dev/null +++ b/client/src/components/UsersModal.tsx @@ -0,0 +1,73 @@ +import React, { FC, useState, ChangeEvent } from "react"; +import { Modal } from "./Modal"; +import { AvatarList } from "./AvatarList"; +import { User } from "../types/User"; +import { FilterBar } from "./FilterBar"; + +interface IProps { + show: boolean; + handleClose: () => void; + users: User[]; +} + +export const UsersModal: FC = ({ show, handleClose, users }) => { + const [filterText, setFilterText] = useState(""); + const handleChange: (e: ChangeEvent) => void = ( + e: ChangeEvent + ) => { + setFilterText(e.target.value); + }; + return ( + +
    +
    +

    Manage users

    +
    +
    + + close + +
    +
    +
    + + setFilterText("")} + handleChange={handleChange} + /> +
    +
    +
      + {users.map((u: User) => ( +
    • +
      + false} + // checked + /> + + {u.fullName} + {u.fullName} + +
      +
    • + ))} +
    +
    +
    + ); +}; diff --git a/client/src/pages/ProjectPage.tsx b/client/src/pages/ProjectPage.tsx index f0f03fd..43528c7 100644 --- a/client/src/pages/ProjectPage.tsx +++ b/client/src/pages/ProjectPage.tsx @@ -1,15 +1,16 @@ -import React, { FC } from "react"; +import React, { FC, useState } from "react"; +import ProjectVM from "../VM/ProjectVM"; import { Header } from "../components/Header"; import { AvatarList } from "../components/AvatarList"; import { ProgressBar } from "../components/ProgressBar"; -import ProjectVM from "../VM/ProjectVM"; import { TabRouter } from "../components/TabRouter"; import { FloatingButton } from "../components/FloatingButton"; -import { Modal } from "../components/Modal"; +import { UsersModal } from "../components/UsersModal"; interface IProps { viewModel: ProjectVM; } + export const ProjectPage: FC = ({ viewModel }) => { const { title, @@ -23,7 +24,9 @@ export const ProjectPage: FC = ({ viewModel }) => { files, activities } = viewModel; + const tabNames: string[] = ["Tickets", "Files", "Activity"]; + const [showModal, setShowModal] = useState(false); return (
    @@ -31,7 +34,17 @@ export const ProjectPage: FC = ({ viewModel }) => {
    - + setShowModal(true)} + /> + setShowModal(false)} + />
    {
    + + + + {/* From 056849e51c539d0bc409a31f5332dac4beeabe40 Mon Sep 17 00:00:00 2001 From: Ruidy Nemausat Date: Mon, 24 Feb 2020 10:27:13 +0100 Subject: [PATCH 21/21] use switch statement in error controller. Added submit button in modal form. Changed appusers endpoint to users --- .gitignore | 3 +- Controllers/AppUsersController.cs | 4 +-- README.md | 1 + Scripts/apiQueries.sh | 1 + Scripts/authentication.sh | 1 + client/src/components/Modal.tsx | 10 +++--- client/src/components/UsersModal.tsx | 32 +++++++++++++++++++- client/src/controllers/ErrorController.tsx | 12 ++++++-- client/src/controllers/ProjectController.tsx | 5 ++- 9 files changed, 56 insertions(+), 13 deletions(-) create mode 100755 Scripts/apiQueries.sh create mode 100755 Scripts/authentication.sh diff --git a/.gitignore b/.gitignore index 01d8a9f..b033101 100644 --- a/.gitignore +++ b/.gitignore @@ -7,5 +7,4 @@ app.db* .DS_Store app.db client/node_modules -client/src/pages/TestPage.tsx -Scripts/ +client/src/pages/TestPage.tsx \ No newline at end of file diff --git a/Controllers/AppUsersController.cs b/Controllers/AppUsersController.cs index 34a1f72..d3ed49a 100644 --- a/Controllers/AppUsersController.cs +++ b/Controllers/AppUsersController.cs @@ -9,8 +9,8 @@ using Microsoft.AspNetCore.Authorization; namespace TicketManager.Controllers { - [Authorize] - [Route("api/v1/[controller]")] + // [Authorize] + [Route("api/v1/users")] [ApiController] public class UsersController : ControllerBase { diff --git a/README.md b/README.md index 01870bc..17b770b 100644 --- a/README.md +++ b/README.md @@ -46,3 +46,4 @@ - [ ] logging - [ ] check useRef, useReducer, dispatch - [ ] error page redirect when offline. +- [ ] ticket/files/activities list placeholders when empty diff --git a/Scripts/apiQueries.sh b/Scripts/apiQueries.sh new file mode 100755 index 0000000..08cee4e --- /dev/null +++ b/Scripts/apiQueries.sh @@ -0,0 +1 @@ +curl --insecure https://localhost:5001/api/v1/ \ No newline at end of file diff --git a/Scripts/authentication.sh b/Scripts/authentication.sh new file mode 100755 index 0000000..3c54e42 --- /dev/null +++ b/Scripts/authentication.sh @@ -0,0 +1 @@ +dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer \ No newline at end of file diff --git a/client/src/components/Modal.tsx b/client/src/components/Modal.tsx index d826e40..73595e6 100644 --- a/client/src/components/Modal.tsx +++ b/client/src/components/Modal.tsx @@ -11,14 +11,14 @@ export const Modal: FC = ({ handleClose, show, children }) => { return (
    {children}
    - {/*
    +
    -
    */} +
    ); }; diff --git a/client/src/components/UsersModal.tsx b/client/src/components/UsersModal.tsx index 24ab07a..0cf92a5 100644 --- a/client/src/components/UsersModal.tsx +++ b/client/src/components/UsersModal.tsx @@ -1,8 +1,11 @@ -import React, { FC, useState, ChangeEvent } from "react"; +import React, { FC, useState, ChangeEvent, useEffect } from "react"; import { Modal } from "./Modal"; import { AvatarList } from "./AvatarList"; import { User } from "../types/User"; import { FilterBar } from "./FilterBar"; +import { HttpResponse } from "../types/HttpResponse"; +import { get } from "../utils/http"; +import { Constants } from "../utils/Constants"; interface IProps { show: boolean; @@ -17,6 +20,32 @@ export const UsersModal: FC = ({ show, handleClose, users }) => { ) => { setFilterText(e.target.value); }; + const [allUsers, setAllUsers] = useState(); + + async function httpGet(): Promise { + try { + const response: HttpResponse = await get( + `${Constants.usersURI}` + ); + if (response.parsedBody !== undefined) { + setAllUsers(response.parsedBody); + // setIsLoading(false); + } + } catch (ex) { + // setHasError(true); + // setError(ex); + } + } + + useEffect(() => { + // if (id !== undefined) { + httpGet(); + // } else { + // setHasError(true); + // setError("Bad Request"); + // } + }, []); + return (
    @@ -40,6 +69,7 @@ export const UsersModal: FC = ({ show, handleClose, users }) => { handleChange={handleChange} />
    + {/*
    {allUsers}
    */}
      {users.map((u: User) => ( diff --git a/client/src/controllers/ErrorController.tsx b/client/src/controllers/ErrorController.tsx index e36007a..4376691 100644 --- a/client/src/controllers/ErrorController.tsx +++ b/client/src/controllers/ErrorController.tsx @@ -6,6 +6,14 @@ interface IProps { } export const ErrorController: FC = ({ error }) => { - if (error === "Not Found") return ; - return <>; + switch (error) { + case "Bad Request": + return ; + + case "Not Found": + return ; + + default: + return ; + } }; diff --git a/client/src/controllers/ProjectController.tsx b/client/src/controllers/ProjectController.tsx index c43e9e6..e6d37fe 100644 --- a/client/src/controllers/ProjectController.tsx +++ b/client/src/controllers/ProjectController.tsx @@ -13,7 +13,7 @@ export const ProjectController: FC = () => { const [project, setProject] = useState({} as Project); const [isLoading, setIsLoading] = useState(true); const [hasError, setHasError] = useState(false); - const [error, setError] = useState(); + const [error, setError] = useState(""); const { id } = useParams(); async function httpGet(id: string): Promise { @@ -34,6 +34,9 @@ export const ProjectController: FC = () => { useEffect(() => { if (id !== undefined) { httpGet(id); + } else { + setHasError(true); + setError("Bad Request"); } }, [id]);