mirror of
https://github.com/rjNemo/ticket_manager
synced 2026-06-06 00:36:39 +00:00
pull signin
This commit is contained in:
commit
1f76be84e8
99 changed files with 999 additions and 792 deletions
|
|
@ -13,7 +13,7 @@ using TicketManager.Resources;
|
||||||
|
|
||||||
namespace TicketManager.Controllers
|
namespace TicketManager.Controllers
|
||||||
{
|
{
|
||||||
// [Authorize]
|
[Authorize]
|
||||||
[Produces("application/json")]
|
[Produces("application/json")]
|
||||||
[Route("api/v1/users")]
|
[Route("api/v1/users")]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
|
|
@ -64,7 +64,7 @@ namespace TicketManager.Controllers
|
||||||
[HttpGet("{id}")]
|
[HttpGet("{id}")]
|
||||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
public async Task<ActionResult<AppUserDTO>> GetUser(Guid id)
|
public async Task<ActionResult<AppUserDTO>> GetUser(string id)
|
||||||
{
|
{
|
||||||
var user = await _context.AppUsers
|
var user = await _context.AppUsers
|
||||||
.Include(u => u.Assignments)
|
.Include(u => u.Assignments)
|
||||||
|
|
@ -103,7 +103,7 @@ namespace TicketManager.Controllers
|
||||||
[HttpPut("{id}")]
|
[HttpPut("{id}")]
|
||||||
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
[ProducesResponseType(StatusCodes.Status204NoContent)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
public async Task<IActionResult> PutUser(Guid id, AppUser user)
|
public async Task<IActionResult> PutUser(string id, AppUser user)
|
||||||
{
|
{
|
||||||
if (id != user.Id)
|
if (id != user.Id)
|
||||||
{
|
{
|
||||||
|
|
@ -159,6 +159,7 @@ namespace TicketManager.Controllers
|
||||||
|
|
||||||
var user = new AppUser()
|
var user = new AppUser()
|
||||||
{
|
{
|
||||||
|
Id = userDto.Id,
|
||||||
FirstName = userDto.FirstName,
|
FirstName = userDto.FirstName,
|
||||||
LastName = userDto.LastName,
|
LastName = userDto.LastName,
|
||||||
Presentation = userDto.Presentation,
|
Presentation = userDto.Presentation,
|
||||||
|
|
@ -202,7 +203,7 @@ namespace TicketManager.Controllers
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("{id}/projects")]
|
[HttpGet("{id}/projects")]
|
||||||
public async Task<ActionResult<IEnumerable<ProjectDTORead>>> GetAppUserProjects(Guid id)
|
public async Task<ActionResult<IEnumerable<ProjectDTORequest>>> GetAppUserProjects(string id)
|
||||||
{
|
{
|
||||||
var user = await _context.AppUsers
|
var user = await _context.AppUsers
|
||||||
.Include(u => u.Assignments)
|
.Include(u => u.Assignments)
|
||||||
|
|
@ -218,7 +219,7 @@ namespace TicketManager.Controllers
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("{id}/tickets/")]
|
[HttpGet("{id}/tickets/")]
|
||||||
public async Task<ActionResult<IEnumerable<TicketDTORead>>> GetAppUserTickets(Guid id)
|
public async Task<ActionResult<IEnumerable<TicketDTORead>>> GetAppUserTickets(string id)
|
||||||
{
|
{
|
||||||
var user = await _context.AppUsers
|
var user = await _context.AppUsers
|
||||||
.Include(u => u.Assignments)
|
.Include(u => u.Assignments)
|
||||||
|
|
@ -233,7 +234,7 @@ namespace TicketManager.Controllers
|
||||||
return user.GetTickets().Select(t => new TicketDTORead(t)).ToList();
|
return user.GetTickets().Select(t => new TicketDTORead(t)).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool UserExists(Guid id)
|
private bool UserExists(string id)
|
||||||
{
|
{
|
||||||
return _context.AppUsers.Any(e => e.Id == id);
|
return _context.AppUsers.Any(e => e.Id == id);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ using System;
|
||||||
namespace TicketManager.Controllers
|
namespace TicketManager.Controllers
|
||||||
{
|
{
|
||||||
// [Authorize(Roles = "Admin")]
|
// [Authorize(Roles = "Admin")]
|
||||||
// [Authorize]
|
[Authorize]
|
||||||
[Produces("application/json")]
|
[Produces("application/json")]
|
||||||
[Route("api/v1/[controller]")]
|
[Route("api/v1/[controller]")]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
|
|
@ -180,11 +180,15 @@ namespace TicketManager.Controllers
|
||||||
EndingDate = projectDto.EndingDate,
|
EndingDate = projectDto.EndingDate,
|
||||||
Manager = await _context.AppUsers.FindAsync(projectDto.ManagerId)
|
Manager = await _context.AppUsers.FindAsync(projectDto.ManagerId)
|
||||||
};
|
};
|
||||||
// project.LogAction(
|
|
||||||
// $"{project.Title} has been created by {project.Manager.FullName}.",
|
|
||||||
// ActivityType.StartTask);
|
|
||||||
|
|
||||||
_context.Projects.Add(project);
|
_context.Projects.Add(project);
|
||||||
|
_context.Assignments.Add(new Assignment()
|
||||||
|
{
|
||||||
|
Project = project,
|
||||||
|
ProjectId = project.Id,
|
||||||
|
User = project.Manager,
|
||||||
|
UserId = project.Manager.Id
|
||||||
|
});
|
||||||
await _context.SaveChangesAsync();
|
await _context.SaveChangesAsync();
|
||||||
var dto = new ProjectDTO(project);
|
var dto = new ProjectDTO(project);
|
||||||
return CreatedAtAction("GetProject", new { id = project.Id }, dto);
|
return CreatedAtAction("GetProject", new { id = project.Id }, dto);
|
||||||
|
|
@ -271,7 +275,7 @@ namespace TicketManager.Controllers
|
||||||
[HttpPatch("{id}/members")]
|
[HttpPatch("{id}/members")]
|
||||||
public async Task<ActionResult<Project>> SetProjectMembers(
|
public async Task<ActionResult<Project>> SetProjectMembers(
|
||||||
[FromRoute] int id,
|
[FromRoute] int id,
|
||||||
[FromBody] Guid[] membersId)
|
[FromBody] string[] membersId)
|
||||||
{
|
{
|
||||||
Project project = await _context.Projects
|
Project project = await _context.Projects
|
||||||
.Include(p => p.Assignments)
|
.Include(p => p.Assignments)
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ using TicketManager.Models;
|
||||||
|
|
||||||
namespace TicketManager.Controllers
|
namespace TicketManager.Controllers
|
||||||
{
|
{
|
||||||
// [Authorize]
|
[Authorize]
|
||||||
[Route("api/v1/[controller]")]
|
[Route("api/v1/[controller]")]
|
||||||
[ApiController]
|
[ApiController]
|
||||||
public class TicketsController : ControllerBase
|
public class TicketsController : ControllerBase
|
||||||
|
|
@ -105,6 +105,9 @@ namespace TicketManager.Controllers
|
||||||
Description = ticketDto.Description,
|
Description = ticketDto.Description,
|
||||||
EndingDate = ticketDto.EndingDate,
|
EndingDate = ticketDto.EndingDate,
|
||||||
CreatorId = ticketDto.CreatorId,
|
CreatorId = ticketDto.CreatorId,
|
||||||
|
Category = (Category)ticketDto.Category,
|
||||||
|
Impact = (Impact)ticketDto.Impact,
|
||||||
|
Difficulty = (Difficulty)ticketDto.Difficulty,
|
||||||
Project = await _context.Projects.FindAsync(ticketDto.ProjectId)
|
Project = await _context.Projects.FindAsync(ticketDto.ProjectId)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ namespace TicketManager.Models
|
||||||
{
|
{
|
||||||
public class AppUser
|
public class AppUser
|
||||||
{
|
{
|
||||||
public Guid Id { get; set; }
|
public string Id { get; set; }
|
||||||
|
|
||||||
[Required]
|
[Required]
|
||||||
[StringLength(50)]
|
[StringLength(50)]
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ namespace TicketManager.Models
|
||||||
public class Assignment
|
public class Assignment
|
||||||
{
|
{
|
||||||
public AppUser User { get; set; }
|
public AppUser User { get; set; }
|
||||||
public Guid UserId { get; set; }
|
public string UserId { get; set; }
|
||||||
public Project Project { get; set; }
|
public Project Project { get; set; }
|
||||||
public int ProjectId { get; set; }
|
public int ProjectId { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ namespace TicketManager.Models
|
||||||
public Impact Impact { get; set; } = Impact.Undefined;
|
public Impact Impact { get; set; } = Impact.Undefined;
|
||||||
public Difficulty Difficulty { get; set; } = Difficulty.Undefined;
|
public Difficulty Difficulty { get; set; } = Difficulty.Undefined;
|
||||||
public Category Category { get; set; } = Category.Undefined;
|
public Category Category { get; set; } = Category.Undefined;
|
||||||
public Guid CreatorId { get; set; }
|
public string CreatorId { get; set; }
|
||||||
|
|
||||||
[Display(Name = "Project")]
|
[Display(Name = "Project")]
|
||||||
public Project Project { get; set; }
|
public Project Project { get; set; }
|
||||||
|
|
|
||||||
|
|
@ -60,3 +60,6 @@
|
||||||
- [ ] Query progression info in UserPage
|
- [ ] Query progression info in UserPage
|
||||||
- [x] Add info fields in New Ticket Form
|
- [x] Add info fields in New Ticket Form
|
||||||
- [ ] Filter users in Users Modal
|
- [ ] Filter users in Users Modal
|
||||||
|
- [ ] EditForms for Project and Ticket
|
||||||
|
- [ ] Admin Page
|
||||||
|
- [ ] Use auth0 user info to create appUser account
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ namespace TicketManager.Resources
|
||||||
Tickets = user.GetTickets().Select(u => new TicketDTORead(u)).ToList();
|
Tickets = user.GetTickets().Select(u => new TicketDTORead(u)).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Guid Id { get; set; }
|
public string Id { get; set; }
|
||||||
|
|
||||||
public string FirstName { get; set; }
|
public string FirstName { get; set; }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ namespace TicketManager.Resources
|
||||||
Picture = user.Picture;
|
Picture = user.Picture;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Guid Id { get; set; }
|
public string Id { get; set; }
|
||||||
|
|
||||||
public string FirstName { get; set; }
|
public string FirstName { get; set; }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@ namespace TicketManager.Resources
|
||||||
{
|
{
|
||||||
public class NewAppUserDTO
|
public class NewAppUserDTO
|
||||||
{
|
{
|
||||||
|
public string Id { get; set; }
|
||||||
|
|
||||||
[Required]
|
[Required]
|
||||||
public string FirstName { get; set; }
|
public string FirstName { get; set; }
|
||||||
public string LastName { get; set; }
|
public string LastName { get; set; }
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,6 @@ namespace TicketManager.Resources
|
||||||
[Required]
|
[Required]
|
||||||
public DateTime EndingDate { get; set; }
|
public DateTime EndingDate { get; set; }
|
||||||
[Required]
|
[Required]
|
||||||
public Guid ManagerId { get; set; }
|
public string ManagerId { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -16,13 +16,13 @@ namespace TicketManager.Resources
|
||||||
[DataType(DataType.Date)]
|
[DataType(DataType.Date)]
|
||||||
public DateTime EndingDate { get; set; }
|
public DateTime EndingDate { get; set; }
|
||||||
|
|
||||||
public string Impact { get; set; }
|
public int Impact { get; set; }
|
||||||
|
|
||||||
public string Difficulty { get; set; }
|
public int Difficulty { get; set; }
|
||||||
|
|
||||||
public string Category { get; set; }
|
public int Category { get; set; }
|
||||||
[Required]
|
[Required]
|
||||||
public Guid CreatorId { get; set; }
|
public string CreatorId { get; set; }
|
||||||
[Required]
|
[Required]
|
||||||
public int ProjectId { get; set; }
|
public int ProjectId { get; set; }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ namespace TicketManager.Resources
|
||||||
|
|
||||||
public string Category { get; set; }
|
public string Category { get; set; }
|
||||||
|
|
||||||
public Guid CreatorId { get; set; }
|
public string CreatorId { get; set; }
|
||||||
|
|
||||||
public ProjectDTORead Project { get; set; }
|
public ProjectDTORead Project { get; set; }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ namespace TicketManager.Resources
|
||||||
|
|
||||||
public string Category { get; set; }
|
public string Category { get; set; }
|
||||||
|
|
||||||
public Guid CreatorId { get; set; }
|
public string CreatorId { get; set; }
|
||||||
public List<Note> Notes { get; set; } = new List<Note>();
|
public List<Note> Notes { get; set; } = new List<Note>();
|
||||||
|
|
||||||
public List<File> Files { get; set; } = new List<File>();
|
public List<File> Files { get; set; } = new List<File>();
|
||||||
|
|
|
||||||
BIN
app.db
BIN
app.db
Binary file not shown.
85
client/package-lock.json
generated
85
client/package-lock.json
generated
|
|
@ -1288,22 +1288,35 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@material-ui/core": {
|
"@material-ui/core": {
|
||||||
"version": "4.9.8",
|
"version": "4.9.13",
|
||||||
"resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.9.8.tgz",
|
"resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.9.13.tgz",
|
||||||
"integrity": "sha512-4cslpG6oLoPWUfwPkX+hvbak4hAGiOfgXOu/UIYeeMrtsTEebC0Mirjoby7zhS4ny86YI3rXEFW6EZDmlj5n5w==",
|
"integrity": "sha512-GEXNwUr+laZ0N+F1efmHB64Fyg+uQIRXLqbSejg3ebSXgLYNpIjnMOPRfWdu4rICq0dAIgvvNXGkKDMcf3AMpA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/runtime": "^7.4.4",
|
"@babel/runtime": "^7.4.4",
|
||||||
"@material-ui/styles": "^4.9.6",
|
"@material-ui/react-transition-group": "^4.3.0",
|
||||||
"@material-ui/system": "^4.9.6",
|
"@material-ui/styles": "^4.9.13",
|
||||||
"@material-ui/types": "^5.0.0",
|
"@material-ui/system": "^4.9.13",
|
||||||
"@material-ui/utils": "^4.9.6",
|
"@material-ui/types": "^5.0.1",
|
||||||
|
"@material-ui/utils": "^4.9.12",
|
||||||
"@types/react-transition-group": "^4.2.0",
|
"@types/react-transition-group": "^4.2.0",
|
||||||
"clsx": "^1.0.2",
|
"clsx": "^1.0.4",
|
||||||
"hoist-non-react-statics": "^3.3.2",
|
"hoist-non-react-statics": "^3.3.2",
|
||||||
"popper.js": "^1.14.1",
|
"popper.js": "^1.16.1-lts",
|
||||||
"prop-types": "^15.7.2",
|
"prop-types": "^15.7.2",
|
||||||
"react-is": "^16.8.0",
|
"react-is": "^16.8.0",
|
||||||
"react-transition-group": "^4.3.0"
|
"react-transition-group": "^4.3.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@material-ui/utils": {
|
||||||
|
"version": "4.9.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-4.9.12.tgz",
|
||||||
|
"integrity": "sha512-/0rgZPEOcZq5CFA4+4n6Q6zk7fi8skHhH2Bcra8R3epoJEYy5PL55LuMazPtPH1oKeRausDV/Omz4BbgFsn1HQ==",
|
||||||
|
"requires": {
|
||||||
|
"@babel/runtime": "^7.4.4",
|
||||||
|
"prop-types": "^15.7.2",
|
||||||
|
"react-is": "^16.8.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@material-ui/icons": {
|
"@material-ui/icons": {
|
||||||
|
|
@ -1326,16 +1339,27 @@
|
||||||
"react-is": "^16.8.0"
|
"react-is": "^16.8.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@material-ui/react-transition-group": {
|
||||||
|
"version": "4.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@material-ui/react-transition-group/-/react-transition-group-4.3.0.tgz",
|
||||||
|
"integrity": "sha512-CwQ0aXrlUynUTY6sh3UvKuvye1o92en20VGAs6TORnSxUYeRmkX8YeTUN3lAkGiBX1z222FxLFO36WWh6q73rQ==",
|
||||||
|
"requires": {
|
||||||
|
"@babel/runtime": "^7.5.5",
|
||||||
|
"dom-helpers": "^5.0.1",
|
||||||
|
"loose-envify": "^1.4.0",
|
||||||
|
"prop-types": "^15.6.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@material-ui/styles": {
|
"@material-ui/styles": {
|
||||||
"version": "4.9.6",
|
"version": "4.9.13",
|
||||||
"resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.9.6.tgz",
|
"resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.9.13.tgz",
|
||||||
"integrity": "sha512-ijgwStEkw1OZ6gCz18hkjycpr/3lKs1hYPi88O/AUn4vMuuGEGAIrqKVFq/lADmZUNF3DOFIk8LDkp7zmjPxtA==",
|
"integrity": "sha512-lWlXJanBdHQ18jW/yphedRokHcvZD1GdGzUF/wQxKDsHwDDfO45ZkAxuSBI202dG+r1Ph483Z3pFykO2obeSRA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/runtime": "^7.4.4",
|
"@babel/runtime": "^7.4.4",
|
||||||
"@emotion/hash": "^0.8.0",
|
"@emotion/hash": "^0.8.0",
|
||||||
"@material-ui/types": "^5.0.0",
|
"@material-ui/types": "^5.0.1",
|
||||||
"@material-ui/utils": "^4.9.6",
|
"@material-ui/utils": "^4.9.6",
|
||||||
"clsx": "^1.0.2",
|
"clsx": "^1.0.4",
|
||||||
"csstype": "^2.5.2",
|
"csstype": "^2.5.2",
|
||||||
"hoist-non-react-statics": "^3.3.2",
|
"hoist-non-react-statics": "^3.3.2",
|
||||||
"jss": "^10.0.3",
|
"jss": "^10.0.3",
|
||||||
|
|
@ -1350,9 +1374,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@material-ui/system": {
|
"@material-ui/system": {
|
||||||
"version": "4.9.6",
|
"version": "4.9.13",
|
||||||
"resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.9.6.tgz",
|
"resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.9.13.tgz",
|
||||||
"integrity": "sha512-QtfoAePyqXoZ2HUVSwGb1Ro0kucMCvVjbI0CdYIR21t0Opgfm1Oer6ni9P5lfeXA39xSt0wCierw37j+YES48Q==",
|
"integrity": "sha512-6AlpvdW6KJJ5bF1Xo2OD13sCN8k+nlL36412/bWnWZOKIfIMo/Lb8c8d1DOIaT/RKWxTEUaWnKZjabVnA3eZjA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/runtime": "^7.4.4",
|
"@babel/runtime": "^7.4.4",
|
||||||
"@material-ui/utils": "^4.9.6",
|
"@material-ui/utils": "^4.9.6",
|
||||||
|
|
@ -1360,9 +1384,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@material-ui/types": {
|
"@material-ui/types": {
|
||||||
"version": "5.0.0",
|
"version": "5.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/@material-ui/types/-/types-5.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@material-ui/types/-/types-5.0.1.tgz",
|
||||||
"integrity": "sha512-UeH2BuKkwDndtMSS0qgx1kCzSMw+ydtj0xx/XbFtxNSTlXydKwzs5gVW5ZKsFlAkwoOOQ9TIsyoCC8hq18tOwg=="
|
"integrity": "sha512-wURPSY7/3+MAtng3i26g+WKwwNE3HEeqa/trDBR5+zWKmcjO+u9t7Npu/J1r+3dmIa/OeziN9D/18IrBKvKffw=="
|
||||||
},
|
},
|
||||||
"@material-ui/utils": {
|
"@material-ui/utils": {
|
||||||
"version": "4.9.6",
|
"version": "4.9.6",
|
||||||
|
|
@ -3779,11 +3803,11 @@
|
||||||
"integrity": "sha1-2bkoGtz9jO2TW9urqDeGiX9k6ZY="
|
"integrity": "sha1-2bkoGtz9jO2TW9urqDeGiX9k6ZY="
|
||||||
},
|
},
|
||||||
"css-vendor": {
|
"css-vendor": {
|
||||||
"version": "2.0.7",
|
"version": "2.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-2.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-2.0.8.tgz",
|
||||||
"integrity": "sha512-VS9Rjt79+p7M0WkPqcAza4Yq1ZHrsHrwf7hPL/bjQB+c1lwmAI+1FXxYTYt818D/50fFVflw0XKleiBN5RITkg==",
|
"integrity": "sha512-x9Aq0XTInxrkuFeHKbYC7zWY8ai7qJ04Kxd9MnvbC1uO5DagxoHQjm4JvG+vCdXOoFtCjbL2XSZfxmoYa9uQVQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/runtime": "^7.6.2",
|
"@babel/runtime": "^7.8.3",
|
||||||
"is-in-browser": "^1.0.2"
|
"is-in-browser": "^1.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -4223,9 +4247,9 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": {
|
"@babel/runtime": {
|
||||||
"version": "7.9.2",
|
"version": "7.9.6",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.9.2.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.9.6.tgz",
|
||||||
"integrity": "sha512-NE2DtOdufG7R5vnfQUTehdTfNycfUANEtCa9PssN9O/xmTzP4E08UI797ixaei6hBEVL9BI/PsdJS5x7mWoB9Q==",
|
"integrity": "sha512-64AF1xY3OAkFHqOb9s4jpgk1Mm5vDZ4L3acHvAml+53nO1XbXLuDodsVpO4OIUsmemlUHMxNdYMNJmsvOwLrvQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"regenerator-runtime": "^0.13.4"
|
"regenerator-runtime": "^0.13.4"
|
||||||
}
|
}
|
||||||
|
|
@ -12926,9 +12950,10 @@
|
||||||
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
|
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
|
||||||
},
|
},
|
||||||
"typescript": {
|
"typescript": {
|
||||||
"version": "3.7.5",
|
"version": "3.8.3",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.5.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.8.3.tgz",
|
||||||
"integrity": "sha512-/P5lkRXkWHNAbcJIiHPfRoKqyd7bsyCma1hZNUGfn20qm64T6ZBlrzprymeu918H+mB/0rIg2gGK/BXkhhYgBw=="
|
"integrity": "sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==",
|
||||||
|
"dev": true
|
||||||
},
|
},
|
||||||
"underscore": {
|
"underscore": {
|
||||||
"version": "1.9.2",
|
"version": "1.9.2",
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@auth0/auth0-spa-js": "^1.6.4",
|
"@auth0/auth0-spa-js": "^1.6.4",
|
||||||
"@material-ui/core": "^4.9.8",
|
"@material-ui/core": "^4.9.13",
|
||||||
"@material-ui/icons": "^4.9.1",
|
"@material-ui/icons": "^4.9.1",
|
||||||
"@material-ui/lab": "^4.0.0-alpha.47",
|
"@material-ui/lab": "^4.0.0-alpha.47",
|
||||||
"@testing-library/jest-dom": "^4.2.4",
|
"@testing-library/jest-dom": "^4.2.4",
|
||||||
|
|
@ -24,7 +24,7 @@
|
||||||
"react-router-dom": "^5.1.2",
|
"react-router-dom": "^5.1.2",
|
||||||
"react-scripts": "3.3.1",
|
"react-scripts": "3.3.1",
|
||||||
"react-swipeable-views": "^0.13.9",
|
"react-swipeable-views": "^0.13.9",
|
||||||
"typescript": "^3.7.5",
|
"typescript": "^3.8.3",
|
||||||
"underscore": "^1.9.2"
|
"underscore": "^1.9.2"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
@ -48,4 +48,4 @@
|
||||||
"last 1 safari version"
|
"last 1 safari version"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -11,12 +11,6 @@
|
||||||
/>
|
/>
|
||||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
||||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||||
|
|
||||||
<!-- <link
|
|
||||||
rel="stylesheet"
|
|
||||||
href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css"
|
|
||||||
/>
|
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script> -->
|
|
||||||
<link
|
<link
|
||||||
rel="stylesheet"
|
rel="stylesheet"
|
||||||
href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap"
|
href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap"
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"short_name": "React App",
|
"short_name": "BugBuster",
|
||||||
"name": "Create React App Sample",
|
"name": "BugBuster | Project Management",
|
||||||
"icons": [
|
"icons": [
|
||||||
{
|
{
|
||||||
"src": "favicon.ico",
|
"src": "favicon.ico",
|
||||||
|
|
@ -22,4 +22,4 @@
|
||||||
"display": "standalone",
|
"display": "standalone",
|
||||||
"theme_color": "#000000",
|
"theme_color": "#000000",
|
||||||
"background_color": "#ffffff"
|
"background_color": "#ffffff"
|
||||||
}
|
}
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import { render } from '@testing-library/react';
|
|
||||||
import App from './App';
|
|
||||||
|
|
||||||
test('renders learn react link', () => {
|
|
||||||
const { getByText } = render(<App />);
|
|
||||||
const linkElement = getByText(/learn react/i);
|
|
||||||
expect(linkElement).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
|
|
@ -1,21 +1,17 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Router } from "react-router-dom";
|
import { Router } from "react-router-dom";
|
||||||
import { useAuth0 } from "./authentication/auth0";
|
import { useAuth0 } from "./authentication/auth0";
|
||||||
import * as createHistory from "history";
|
|
||||||
// import history from "./utils/history";
|
|
||||||
import MainLayout from "./layouts/MainLayout";
|
import MainLayout from "./layouts/MainLayout";
|
||||||
import { AppRouter } from "./utils/router";
|
import AppRouter from "./routes/AppRouter";
|
||||||
|
import history from "./utils/history";
|
||||||
export const history = createHistory.createBrowserHistory();
|
import Preloader from "./components/Preloader";
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
const { loading } = useAuth0();
|
const { loading } = useAuth0();
|
||||||
|
|
||||||
if (loading) {
|
return loading ? (
|
||||||
return <div>Loading...</div>;
|
<Preloader />
|
||||||
}
|
) : (
|
||||||
|
|
||||||
return (
|
|
||||||
<Router history={history}>
|
<Router history={history}>
|
||||||
<MainLayout>
|
<MainLayout>
|
||||||
<AppRouter />
|
<AppRouter />
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import { Ticket } from "../types/Ticket";
|
import Activity from "../types/Activity";
|
||||||
import { Project } from "../types/Project";
|
import AppFile from "../types/AppFile";
|
||||||
import { AppFile } from "../types/AppFile";
|
import Project from "../types/Project";
|
||||||
import { Activity } from "../types/Activity";
|
import Ticket from "../types/Ticket";
|
||||||
import { User } from "../types/User";
|
import User from "../types/User";
|
||||||
import { getRemainingdays } from "../utils/methods";
|
import getRemainingdays from "../utils/methods";
|
||||||
|
|
||||||
export default class ProjectVM {
|
export default class ProjectVM {
|
||||||
public id: number;
|
public id: number;
|
||||||
|
|
@ -47,7 +47,7 @@ export default class ProjectVM {
|
||||||
this.ticketsDone =
|
this.ticketsDone =
|
||||||
this.tickets === undefined
|
this.tickets === undefined
|
||||||
? 0
|
? 0
|
||||||
: this.tickets.filter(t => t.status === "Done").length;
|
: this.tickets.filter((t) => t.status === "Done").length;
|
||||||
this.remainingDays = getRemainingdays(project.endingDate);
|
this.remainingDays = getRemainingdays(project.endingDate);
|
||||||
this.allProjects = allProjects;
|
this.allProjects = allProjects;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import { Ticket } from "../types/Ticket";
|
import Project from "../types/Project";
|
||||||
import { Project } from "../types/Project";
|
import Ticket from "../types/Ticket";
|
||||||
import { User } from "../types/User";
|
import User from "../types/User";
|
||||||
|
|
||||||
export class TicketVM {
|
export default class TicketVM {
|
||||||
public id: number;
|
public id: number;
|
||||||
public title: string;
|
public title: string;
|
||||||
public description: string;
|
public description: string;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { Project } from "../types/Project";
|
import Activity from "../types/Activity";
|
||||||
import { Ticket } from "../types/Ticket";
|
import Project from "../types/Project";
|
||||||
import { User } from "../types/User";
|
import Ticket from "../types/Ticket";
|
||||||
import { Activity } from "../types/Activity";
|
import User from "../types/User";
|
||||||
|
|
||||||
export class UserVM {
|
export class UserVM {
|
||||||
public id: string;
|
public id: string;
|
||||||
|
|
@ -16,9 +16,8 @@ export class UserVM {
|
||||||
public projects: Project[];
|
public projects: Project[];
|
||||||
public tickets: Ticket[];
|
public tickets: Ticket[];
|
||||||
public activities: Activity[];
|
public activities: Activity[];
|
||||||
public allUsers: User[];
|
|
||||||
|
|
||||||
public constructor(user: User, allUsers: User[]) {
|
public constructor(user: User) {
|
||||||
this.id = user.id;
|
this.id = user.id;
|
||||||
this.firstName = user.firstName;
|
this.firstName = user.firstName;
|
||||||
this.lastName = user.lastName;
|
this.lastName = user.lastName;
|
||||||
|
|
@ -31,6 +30,5 @@ export class UserVM {
|
||||||
this.projects = user.projects;
|
this.projects = user.projects;
|
||||||
this.tickets = user.tickets;
|
this.tickets = user.tickets;
|
||||||
this.activities = user.activities;
|
this.activities = user.activities;
|
||||||
this.allUsers = allUsers;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
// src/react-auth0-spa.js
|
|
||||||
import React, { useState, useEffect, useContext } from "react";
|
import React, { useState, useEffect, useContext } from "react";
|
||||||
import createAuth0Client from "@auth0/auth0-spa-js";
|
import createAuth0Client from "@auth0/auth0-spa-js";
|
||||||
|
|
||||||
|
|
@ -68,6 +67,7 @@ export const Auth0Provider = ({
|
||||||
setIsAuthenticated(true);
|
setIsAuthenticated(true);
|
||||||
setUser(user);
|
setUser(user);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Auth0Context.Provider
|
<Auth0Context.Provider
|
||||||
value={{
|
value={{
|
||||||
|
|
@ -81,7 +81,7 @@ export const Auth0Provider = ({
|
||||||
loginWithRedirect: (...p) => auth0Client.loginWithRedirect(...p),
|
loginWithRedirect: (...p) => auth0Client.loginWithRedirect(...p),
|
||||||
getTokenSilently: (...p) => auth0Client.getTokenSilently(...p),
|
getTokenSilently: (...p) => auth0Client.getTokenSilently(...p),
|
||||||
getTokenWithPopup: (...p) => auth0Client.getTokenWithPopup(...p),
|
getTokenWithPopup: (...p) => auth0Client.getTokenWithPopup(...p),
|
||||||
logout: (...p) => auth0Client.logout(...p)
|
logout: (...p) => auth0Client.logout(...p),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
|
|
||||||
9
client/src/authentication/helpers.ts
Normal file
9
client/src/authentication/helpers.ts
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
/**
|
||||||
|
* retrieve userId
|
||||||
|
* @param user Auth0 user object
|
||||||
|
*/
|
||||||
|
export const getUID = (user: any) => {
|
||||||
|
const { sub } = user;
|
||||||
|
const uid = sub.split("|")[1];
|
||||||
|
return uid;
|
||||||
|
};
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
import React, { FC } from "react";
|
import React, { FC } from "react";
|
||||||
import { Activity } from "../types/Activity";
|
import Activity from "../types/Activity";
|
||||||
|
|
||||||
type IProps = {
|
type IProps = {
|
||||||
activities: Activity[];
|
activities: Activity[];
|
||||||
filterText: string;
|
filterText: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ActivityCollection: FC<IProps> = ({ activities, filterText }) => {
|
const ActivityCollection: FC<IProps> = ({ activities, filterText }) => {
|
||||||
return activities === undefined ? (
|
return activities === undefined ? (
|
||||||
<></>
|
<></>
|
||||||
) : (
|
) : (
|
||||||
|
|
@ -17,7 +17,7 @@ export const ActivityCollection: FC<IProps> = ({ activities, filterText }) => {
|
||||||
) : (
|
) : (
|
||||||
activities
|
activities
|
||||||
.filter(
|
.filter(
|
||||||
a =>
|
(a) =>
|
||||||
a.description
|
a.description
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.includes(filterText.toLowerCase()) ||
|
.includes(filterText.toLowerCase()) ||
|
||||||
|
|
@ -67,3 +67,4 @@ export const ActivityEntry: FC<IFProps> = ({ activity }) => {
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
export default ActivityCollection;
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,8 @@
|
||||||
import React, { FC } from "react";
|
import React, { FC } from "react";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import Avatar from "@material-ui/core/Avatar";
|
import { makeStyles, Theme, createStyles, Avatar } from "@material-ui/core";
|
||||||
import AvatarGroup from "@material-ui/lab/AvatarGroup";
|
import AvatarGroup from "@material-ui/lab/AvatarGroup";
|
||||||
import { User } from "../../types/User";
|
import User from "../../types/User";
|
||||||
import { makeStyles, Theme, createStyles } from "@material-ui/core";
|
|
||||||
|
|
||||||
interface AvatarListProps {
|
interface AvatarListProps {
|
||||||
users: User[];
|
users: User[];
|
||||||
|
|
@ -34,3 +33,5 @@ export const AvatarList: FC<AvatarListProps> = ({ users }) => {
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default AvatarList;
|
||||||
|
|
|
||||||
|
|
@ -12,17 +12,17 @@ const useStyles = makeStyles((theme: Theme) =>
|
||||||
root: {
|
root: {
|
||||||
display: "flex",
|
display: "flex",
|
||||||
"& > *": {
|
"& > *": {
|
||||||
margin: theme.spacing(1)
|
margin: theme.spacing(1),
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
small: {
|
small: {
|
||||||
width: theme.spacing(3),
|
width: theme.spacing(3),
|
||||||
height: theme.spacing(3)
|
height: theme.spacing(3),
|
||||||
},
|
},
|
||||||
large: {
|
large: {
|
||||||
width: theme.spacing(10),
|
width: theme.spacing(10),
|
||||||
height: theme.spacing(10)
|
height: theme.spacing(10),
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -35,3 +35,5 @@ export const UserAvatar: FC<IProps> = ({ picture, alt }) => {
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default UserAvatar;
|
||||||
|
|
|
||||||
|
|
@ -1,30 +1,36 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
import { Link } from "react-router-dom";
|
||||||
|
import {
|
||||||
|
AppBar,
|
||||||
|
Button,
|
||||||
|
IconButton,
|
||||||
|
Toolbar,
|
||||||
|
Typography,
|
||||||
|
Avatar,
|
||||||
|
} from "@material-ui/core";
|
||||||
import { createStyles, makeStyles, Theme } from "@material-ui/core/styles";
|
import { createStyles, makeStyles, Theme } from "@material-ui/core/styles";
|
||||||
import AppBar from "@material-ui/core/AppBar";
|
|
||||||
import Toolbar from "@material-ui/core/Toolbar";
|
|
||||||
import Typography from "@material-ui/core/Typography";
|
|
||||||
import Button from "@material-ui/core/Button";
|
|
||||||
import IconButton from "@material-ui/core/IconButton";
|
|
||||||
import MenuIcon from "@material-ui/icons/Menu";
|
import MenuIcon from "@material-ui/icons/Menu";
|
||||||
|
import * as ROUTES from "../constants/routes";
|
||||||
import { useAuth0 } from "../authentication/auth0";
|
import { useAuth0 } from "../authentication/auth0";
|
||||||
|
import { getUID } from "../authentication/helpers";
|
||||||
|
|
||||||
const useStyles = makeStyles((theme: Theme) =>
|
const useStyles = makeStyles((theme: Theme) =>
|
||||||
createStyles({
|
createStyles({
|
||||||
root: {
|
root: {
|
||||||
flexGrow: 1
|
flexGrow: 1,
|
||||||
},
|
},
|
||||||
menuButton: {
|
menuButton: {
|
||||||
marginRight: theme.spacing(2)
|
marginRight: theme.spacing(2),
|
||||||
},
|
},
|
||||||
title: {
|
title: {
|
||||||
flexGrow: 1
|
flexGrow: 1,
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
export default function ButtonAppBar() {
|
export default function ButtonAppBar() {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const { isAuthenticated, loginWithRedirect, logout } = useAuth0();
|
const { isAuthenticated, loginWithRedirect, logout, user } = useAuth0();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classes.root}>
|
<div className={classes.root}>
|
||||||
|
|
@ -39,18 +45,31 @@ export default function ButtonAppBar() {
|
||||||
<MenuIcon />
|
<MenuIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<Typography variant="h6" className={classes.title}>
|
<Typography variant="h6" className={classes.title}>
|
||||||
<Button color="inherit" href="/">
|
<Button color="inherit" component={Link} to={ROUTES.HOME}>
|
||||||
BugBuster
|
BugBuster
|
||||||
</Button>
|
</Button>
|
||||||
</Typography>
|
</Typography>
|
||||||
{!isAuthenticated ? (
|
{!isAuthenticated ? (
|
||||||
<Button color="inherit" onClick={() => loginWithRedirect({})}>
|
<Button
|
||||||
|
color="secondary"
|
||||||
|
variant="contained"
|
||||||
|
onClick={() => loginWithRedirect({})}
|
||||||
|
>
|
||||||
Log in
|
Log in
|
||||||
</Button>
|
</Button>
|
||||||
) : (
|
) : (
|
||||||
<Button color="inherit" onClick={() => logout()}>
|
<>
|
||||||
Log out
|
<Button
|
||||||
</Button>
|
color="inherit"
|
||||||
|
component={Link}
|
||||||
|
to={`${ROUTES.USERS}/${getUID(user)}`}
|
||||||
|
>
|
||||||
|
<Avatar src={user.picture} />
|
||||||
|
</Button>
|
||||||
|
<Button color="inherit" onClick={() => logout()}>
|
||||||
|
Log out
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</Toolbar>
|
</Toolbar>
|
||||||
</AppBar>
|
</AppBar>
|
||||||
|
|
|
||||||
|
|
@ -9,12 +9,12 @@ interface IProps {
|
||||||
onClick?: (e: MouseEvent) => void;
|
onClick?: (e: MouseEvent) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Button: FC<IProps> = ({
|
const Button: FC<IProps> = ({
|
||||||
size = "small",
|
size = "small",
|
||||||
shape = "",
|
shape = "",
|
||||||
color,
|
color,
|
||||||
onClick,
|
onClick,
|
||||||
children
|
children,
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
|
|
@ -25,3 +25,5 @@ export const Button: FC<IProps> = ({
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default Button;
|
||||||
|
|
|
||||||
|
|
@ -10,13 +10,7 @@ interface IProps {
|
||||||
text?: string;
|
text?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const FloatingButton: FC<IProps> = ({
|
const FloatingButton: FC<IProps> = ({ color, icon, size, text, onClick }) => {
|
||||||
color,
|
|
||||||
icon,
|
|
||||||
size,
|
|
||||||
text,
|
|
||||||
onClick
|
|
||||||
}) => {
|
|
||||||
return (
|
return (
|
||||||
<Fab color={color} aria-label={icon} size={size} onClick={onClick}>
|
<Fab color={color} aria-label={icon} size={size} onClick={onClick}>
|
||||||
<AddIcon />
|
<AddIcon />
|
||||||
|
|
@ -24,3 +18,5 @@ export const FloatingButton: FC<IProps> = ({
|
||||||
</Fab>
|
</Fab>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default FloatingButton;
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,8 @@
|
||||||
import React, { FC, ReactNode } from "react";
|
import React, { FC, ReactNode } from "react";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { makeStyles } from "@material-ui/core/styles";
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
import Card from "@material-ui/core/Card";
|
import { Card, CardActions, CardContent, Typography } from "@material-ui/core";
|
||||||
import CardActions from "@material-ui/core/CardActions";
|
import ProgressBar from "../Progress/ProgressBar";
|
||||||
import CardContent from "@material-ui/core/CardContent";
|
|
||||||
import Typography from "@material-ui/core/Typography";
|
|
||||||
import { ProgressBar } from "../Progress/ProgressBar";
|
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
title?: string;
|
title?: string;
|
||||||
|
|
@ -22,7 +19,7 @@ const useStyles = makeStyles({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export const HorizontalCard: FC<IProps> = ({
|
const HorizontalCard: FC<IProps> = ({
|
||||||
title,
|
title,
|
||||||
link = "#",
|
link = "#",
|
||||||
content,
|
content,
|
||||||
|
|
@ -46,3 +43,5 @@ export const HorizontalCard: FC<IProps> = ({
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default HorizontalCard;
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
import React, { FC } from "react";
|
import React, { FC } from "react";
|
||||||
import { HorizontalCard } from "./HorizontalCard";
|
|
||||||
import { makeStyles, Theme, createStyles } from "@material-ui/core";
|
import { makeStyles, Theme, createStyles } from "@material-ui/core";
|
||||||
import { AvatarList } from "../Avatars/AvatarList";
|
import HorizontalCard from "./HorizontalCard";
|
||||||
import { ProgressInfo } from "../Progress/ProgressInfo";
|
import AvatarList from "../Avatars/AvatarList";
|
||||||
import { User } from "../../types/User";
|
import ProgressInfo from "../Progress/ProgressInfo";
|
||||||
import { getRemainingdays } from "../../utils/methods";
|
import User from "../../types/User";
|
||||||
|
import getRemainingdays from "../../utils/methods";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
title?: string;
|
title?: string;
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import React, { FC, MouseEvent } from "react";
|
import React, { FC, MouseEvent } from "react";
|
||||||
import { Button, Typography, Grid } from "@material-ui/core";
|
import { Button, Typography, Grid } from "@material-ui/core";
|
||||||
import { HorizontalCard } from "./HorizontalCard";
|
import HorizontalCard from "./HorizontalCard";
|
||||||
import TicketChipsArray from "./TicketChipsArray";
|
import TicketChipsArray from "./TicketChipsArray";
|
||||||
import { Ticket } from "../../types/Ticket";
|
import Ticket from "../../types/Ticket";
|
||||||
import { getRemainingdays } from "../../utils/methods";
|
import getRemainingdays from "../../utils/methods";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
ticket?: Ticket;
|
ticket?: Ticket;
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,14 @@
|
||||||
import React, { FC } from "react";
|
import React, { FC } from "react";
|
||||||
|
import {
|
||||||
|
Avatar,
|
||||||
|
ListItemAvatar,
|
||||||
|
List,
|
||||||
|
ListItemText,
|
||||||
|
ListItem,
|
||||||
|
} from "@material-ui/core";
|
||||||
import { createStyles, Theme, makeStyles } from "@material-ui/core/styles";
|
import { createStyles, Theme, makeStyles } from "@material-ui/core/styles";
|
||||||
import List from "@material-ui/core/List";
|
|
||||||
import ListItem from "@material-ui/core/ListItem";
|
|
||||||
import ListItemText from "@material-ui/core/ListItemText";
|
|
||||||
import ListItemAvatar from "@material-ui/core/ListItemAvatar";
|
|
||||||
import Avatar from "@material-ui/core/Avatar";
|
|
||||||
import WorkIcon from "@material-ui/icons/Work";
|
import WorkIcon from "@material-ui/icons/Work";
|
||||||
import { AppFile } from "../types/AppFile";
|
import AppFile from "../types/AppFile";
|
||||||
|
|
||||||
type IProps = {
|
type IProps = {
|
||||||
files: AppFile[];
|
files: AppFile[];
|
||||||
|
|
@ -18,12 +20,12 @@ const useStyles = makeStyles((theme: Theme) =>
|
||||||
root: {
|
root: {
|
||||||
width: "100%",
|
width: "100%",
|
||||||
maxWidth: 360,
|
maxWidth: 360,
|
||||||
backgroundColor: theme.palette.background.paper
|
backgroundColor: theme.palette.background.paper,
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
export const FileCollection: FC<IProps> = ({ files, filterText }) => {
|
const FileCollection: FC<IProps> = ({ files, filterText }) => {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
return (
|
return (
|
||||||
<List className={classes.root}>
|
<List className={classes.root}>
|
||||||
|
|
@ -32,7 +34,7 @@ export const FileCollection: FC<IProps> = ({ files, filterText }) => {
|
||||||
) : (
|
) : (
|
||||||
files
|
files
|
||||||
.filter(
|
.filter(
|
||||||
f =>
|
(f) =>
|
||||||
f.name.toLowerCase().includes(filterText.toLowerCase()) ||
|
f.name.toLowerCase().includes(filterText.toLowerCase()) ||
|
||||||
f.format.toLowerCase().includes(filterText.toLowerCase())
|
f.format.toLowerCase().includes(filterText.toLowerCase())
|
||||||
)
|
)
|
||||||
|
|
@ -61,3 +63,4 @@ export const FileEntry: FC<IFProps> = ({ file }) => {
|
||||||
</ListItem>
|
</ListItem>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
export default FileCollection;
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,7 @@
|
||||||
import React, { FC, ChangeEvent, MouseEvent } from "react";
|
import React, { FC, ChangeEvent, MouseEvent } from "react";
|
||||||
import { useRouteMatch } from "react-router-dom";
|
import { useRouteMatch } from "react-router-dom";
|
||||||
|
import { Grid, TextField } from "@material-ui/core";
|
||||||
import { createStyles, makeStyles, Theme } from "@material-ui/core/styles";
|
import { createStyles, makeStyles, Theme } from "@material-ui/core/styles";
|
||||||
import TextField from "@material-ui/core/TextField";
|
|
||||||
import { Grid } from "@material-ui/core";
|
|
||||||
// import { AccountCircle, FilterList, FilterListSharp } from "@material-ui/icons";
|
|
||||||
|
|
||||||
type IProps = {
|
type IProps = {
|
||||||
filterText: string;
|
filterText: string;
|
||||||
|
|
@ -28,7 +26,7 @@ const useStyles = makeStyles((theme: Theme) =>
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
export const FilterBar: FC<IProps> = ({
|
const FilterBar: FC<IProps> = ({
|
||||||
filterText,
|
filterText,
|
||||||
handleChange,
|
handleChange,
|
||||||
// clearFilterText
|
// clearFilterText
|
||||||
|
|
@ -55,3 +53,4 @@ export const FilterBar: FC<IProps> = ({
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
export default FilterBar;
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
import React, { FC } from "react";
|
import React, { FC } from "react";
|
||||||
import Typography from "@material-ui/core/Typography";
|
import { Link as RouterLink } from "react-router-dom";
|
||||||
|
import { Container, Typography, Link } from "@material-ui/core";
|
||||||
import { makeStyles } from "@material-ui/core/styles";
|
import { makeStyles } from "@material-ui/core/styles";
|
||||||
import Container from "@material-ui/core/Container";
|
|
||||||
import Link from "@material-ui/core/Link";
|
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
brand: string;
|
brand: string;
|
||||||
|
|
@ -11,14 +10,14 @@ interface IProps {
|
||||||
|
|
||||||
const copyParams: IProps = {
|
const copyParams: IProps = {
|
||||||
brand: "BugBuster",
|
brand: "BugBuster",
|
||||||
text: "Made with 🔥"
|
text: "Made with 🔥",
|
||||||
};
|
};
|
||||||
|
|
||||||
const Copyright: FC<IProps> = ({ brand, text }) => {
|
const Copyright: FC<IProps> = ({ brand, text }) => {
|
||||||
return (
|
return (
|
||||||
<Typography variant="body2" color="textSecondary">
|
<Typography variant="body2" color="textSecondary">
|
||||||
{"© "}
|
{"© "}
|
||||||
<Link color="inherit" href="/">
|
<Link color="inherit" component={RouterLink} to="/">
|
||||||
{brand}
|
{brand}
|
||||||
</Link>{" "}
|
</Link>{" "}
|
||||||
{new Date().getFullYear()}
|
{new Date().getFullYear()}
|
||||||
|
|
@ -27,15 +26,15 @@ const Copyright: FC<IProps> = ({ brand, text }) => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const useStyles = makeStyles(theme => ({
|
const useStyles = makeStyles((theme) => ({
|
||||||
footer: {
|
footer: {
|
||||||
padding: theme.spacing(3, 2),
|
padding: theme.spacing(3, 2),
|
||||||
marginTop: "auto",
|
marginTop: "auto",
|
||||||
backgroundColor:
|
backgroundColor:
|
||||||
theme.palette.type === "light"
|
theme.palette.type === "light"
|
||||||
? theme.palette.grey[200]
|
? theme.palette.grey[200]
|
||||||
: theme.palette.grey[800]
|
: theme.palette.grey[800],
|
||||||
}
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export default function Footer() {
|
export default function Footer() {
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ type HeaderProps = {
|
||||||
description: string;
|
description: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const Header: FC<HeaderProps> = ({ title, description }) => {
|
const Header: FC<HeaderProps> = ({ title, description }) => {
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
<Typography variant="h2" component="h2">
|
<Typography variant="h2" component="h2">
|
||||||
|
|
@ -18,3 +18,5 @@ export const Header: FC<HeaderProps> = ({ title, description }) => {
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default Header;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import React, { FC } from "react";
|
import React, { FC } from "react";
|
||||||
|
|
||||||
export const InputField: FC = () => {
|
const InputField: FC = () => {
|
||||||
return (
|
return (
|
||||||
<div className="input-field">
|
<div className="input-field">
|
||||||
<input id="email" type="text" className="validate" />
|
<input id="email" type="text" className="validate" />
|
||||||
|
|
@ -8,3 +8,5 @@ export const InputField: FC = () => {
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default InputField;
|
||||||
|
|
|
||||||
|
|
@ -3,22 +3,20 @@ import { CloudUpload } from "@material-ui/icons";
|
||||||
import { makeStyles, createStyles, Theme } from "@material-ui/core/styles";
|
import { makeStyles, createStyles, Theme } from "@material-ui/core/styles";
|
||||||
import Button from "@material-ui/core/Button";
|
import Button from "@material-ui/core/Button";
|
||||||
|
|
||||||
export const InputFile: FC = () => {
|
const InputFile: FC = () => {
|
||||||
return (
|
return (
|
||||||
<>
|
<form action="/upload">
|
||||||
<form action="/upload">
|
<div className="file-field input-field">
|
||||||
<div className="file-field input-field">
|
<UploadButton>
|
||||||
<UploadButton>
|
<CloudUpload />
|
||||||
<CloudUpload />
|
<input
|
||||||
<input
|
type="file"
|
||||||
type="file"
|
multiple
|
||||||
multiple
|
accept=".doc,.docx,.pdf,.md,.gdoc,.zip,image/*"
|
||||||
accept=".doc,.docx,.pdf,.md,.gdoc,.zip,image/*"
|
/>
|
||||||
/>
|
</UploadButton>
|
||||||
</UploadButton>
|
</div>
|
||||||
</div>
|
</form>
|
||||||
</form>
|
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -26,12 +24,12 @@ const useStyles = makeStyles((theme: Theme) =>
|
||||||
createStyles({
|
createStyles({
|
||||||
root: {
|
root: {
|
||||||
"& > *": {
|
"& > *": {
|
||||||
margin: theme.spacing(1)
|
margin: theme.spacing(1),
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
input: {
|
input: {
|
||||||
display: "none"
|
display: "none",
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -60,3 +58,5 @@ const UploadButton: FC = () => {
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default InputFile;
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
import React, { FC, useState, ChangeEvent, MouseEvent } from "react";
|
import React, { FC, useState, ChangeEvent, MouseEvent } from "react";
|
||||||
import { ActivityCollection } from "../ActivityCollection";
|
import ActivityCollection from "../ActivityCollection";
|
||||||
import { Activity } from "../../types/Activity";
|
import FilterBar from "../FilterBar";
|
||||||
import { FilterBar } from "../FilterBar";
|
import Activity from "../../types/Activity";
|
||||||
|
|
||||||
type IProps = {
|
type IProps = {
|
||||||
activities: Activity[];
|
activities: Activity[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ActivityList: FC<IProps> = ({ activities }) => {
|
const ActivityList: FC<IProps> = ({ activities }) => {
|
||||||
const [filterText, setFilterText] = useState<string>("");
|
const [filterText, setFilterText] = useState<string>("");
|
||||||
const clearFilterText: (e: MouseEvent) => void = (e: MouseEvent) => {
|
const clearFilterText: (e: MouseEvent) => void = (e: MouseEvent) => {
|
||||||
setFilterText("");
|
setFilterText("");
|
||||||
|
|
@ -30,3 +30,5 @@ export const ActivityList: FC<IProps> = ({ activities }) => {
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default ActivityList;
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,15 @@
|
||||||
import React, { FC, useState, ChangeEvent, MouseEvent } from "react";
|
import React, { FC, useState, ChangeEvent, MouseEvent } from "react";
|
||||||
import { AppFile } from "../../types/AppFile";
|
|
||||||
import { FileCollection } from "../FileCollection";
|
|
||||||
import { InputFile } from "../InputFile";
|
|
||||||
import { FilterBar } from "../FilterBar";
|
|
||||||
import { Grid, Typography } from "@material-ui/core";
|
import { Grid, Typography } from "@material-ui/core";
|
||||||
|
import FileCollection from "../FileCollection";
|
||||||
|
import FilterBar from "../FilterBar";
|
||||||
|
import InputFile from "../InputFile";
|
||||||
|
import AppFile from "../../types/AppFile";
|
||||||
|
|
||||||
type IProps = {
|
type IProps = {
|
||||||
files: AppFile[];
|
files: AppFile[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export const FileList: FC<IProps> = ({ files }) => {
|
const FileList: FC<IProps> = ({ files }) => {
|
||||||
const [filterText, setFilterText] = useState<string>("");
|
const [filterText, setFilterText] = useState<string>("");
|
||||||
const clearFilterText = (e: MouseEvent): void => {
|
const clearFilterText = (e: MouseEvent): void => {
|
||||||
setFilterText("");
|
setFilterText("");
|
||||||
|
|
@ -38,3 +38,5 @@ export const FileList: FC<IProps> = ({ files }) => {
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default FileList;
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
import React, { FC, useState, ChangeEvent, MouseEvent } from "react";
|
import React, { FC, useState, ChangeEvent, MouseEvent } from "react";
|
||||||
import { UsersModalEntry } from "../Modals/UsersModalEntry";
|
import FilterBar from "../FilterBar";
|
||||||
import { FilterBar } from "../FilterBar";
|
import UsersModalEntry from "../Modals/UsersModalEntry";
|
||||||
import { User } from "../../types/User";
|
import User from "../../types/User";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
users: User[];
|
users: User[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const MemberList: FC<IProps> = ({ users }) => {
|
const MemberList: FC<IProps> = ({ users }) => {
|
||||||
const [members, setMembers] = useState<User[]>([]);
|
const [members, setMembers] = useState<User[]>([]);
|
||||||
const [filterText, setFilterText] = useState<string>("");
|
const [filterText, setFilterText] = useState<string>("");
|
||||||
const clearFilterText = (e: MouseEvent): void => {
|
const clearFilterText = (e: MouseEvent): void => {
|
||||||
|
|
@ -37,3 +37,5 @@ export const MemberList: FC<IProps> = ({ users }) => {
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default MemberList;
|
||||||
|
|
|
||||||
|
|
@ -6,12 +6,11 @@ import {
|
||||||
createStyles,
|
createStyles,
|
||||||
Theme,
|
Theme,
|
||||||
} from "@material-ui/core";
|
} from "@material-ui/core";
|
||||||
import { FilterBar } from "../FilterBar";
|
import FilterBar from "../FilterBar";
|
||||||
import ProjectCard from "../Cards/ProjectCard";
|
import ProjectCard from "../Cards/ProjectCard";
|
||||||
import { FloatingButton } from "../Buttons/FloatingButton";
|
import FloatingButton from "../Buttons/FloatingButton";
|
||||||
import { NewProjectModal } from "../Modals/NewProjectModal";
|
import NewProjectModal from "../Modals/NewProjectModal";
|
||||||
import { Project } from "../../types/Project";
|
import Project from "../../types/Project";
|
||||||
import { User } from "../../types/User";
|
|
||||||
|
|
||||||
const useStyles = makeStyles((theme: Theme) =>
|
const useStyles = makeStyles((theme: Theme) =>
|
||||||
createStyles({
|
createStyles({
|
||||||
|
|
@ -27,10 +26,9 @@ const useStyles = makeStyles((theme: Theme) =>
|
||||||
|
|
||||||
type IProps = {
|
type IProps = {
|
||||||
projects: Project[];
|
projects: Project[];
|
||||||
allUsers: User[];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ProjectList: FC<IProps> = ({ projects, allUsers }) => {
|
const ProjectList: FC<IProps> = ({ projects }) => {
|
||||||
const [filterText, setFilterText] = useState<string>("");
|
const [filterText, setFilterText] = useState<string>("");
|
||||||
const clearFilterText: (e: MouseEvent) => void = (e: MouseEvent) => {
|
const clearFilterText: (e: MouseEvent) => void = (e: MouseEvent) => {
|
||||||
setFilterText("");
|
setFilterText("");
|
||||||
|
|
@ -59,7 +57,6 @@ export const ProjectList: FC<IProps> = ({ projects, allUsers }) => {
|
||||||
setShowNew(false);
|
setShowNew(false);
|
||||||
}}
|
}}
|
||||||
show={showNew}
|
show={showNew}
|
||||||
allUsers={allUsers}
|
|
||||||
/>
|
/>
|
||||||
<Grid container>
|
<Grid container>
|
||||||
<Grid
|
<Grid
|
||||||
|
|
@ -109,3 +106,5 @@ export const ProjectList: FC<IProps> = ({ projects, allUsers }) => {
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default ProjectList;
|
||||||
|
|
|
||||||
|
|
@ -6,15 +6,14 @@ import {
|
||||||
Theme,
|
Theme,
|
||||||
createStyles,
|
createStyles,
|
||||||
} from "@material-ui/core";
|
} from "@material-ui/core";
|
||||||
import { FloatingButton } from "../Buttons/FloatingButton";
|
import FloatingButton from "../Buttons/FloatingButton";
|
||||||
import { FilterBar } from "../FilterBar";
|
import FilterBar from "../FilterBar";
|
||||||
import { HttpResponse } from "../../types/HttpResponse";
|
|
||||||
import { Ticket } from "../../types/Ticket";
|
|
||||||
import { NewTicketModal } from "../Modals/NewTicketModal";
|
|
||||||
import { Project } from "../../types/Project";
|
|
||||||
import { put } from "../../utils/http";
|
|
||||||
import { Constants } from "../../utils/Constants";
|
|
||||||
import TicketCard from "../Cards/TicketCard";
|
import TicketCard from "../Cards/TicketCard";
|
||||||
|
import NewTicketModal from "../Modals/NewTicketModal";
|
||||||
|
import Ticket from "../../types/Ticket";
|
||||||
|
import Project from "../../types/Project";
|
||||||
|
import { useAuth0 } from "../../authentication/auth0";
|
||||||
|
import { TicketService } from "../../services";
|
||||||
|
|
||||||
const useStyles = makeStyles((theme: Theme) =>
|
const useStyles = makeStyles((theme: Theme) =>
|
||||||
createStyles({
|
createStyles({
|
||||||
|
|
@ -34,7 +33,7 @@ type TicketListProps = {
|
||||||
addButton?: Boolean;
|
addButton?: Boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const TicketList: FC<TicketListProps> = ({
|
const TicketList: FC<TicketListProps> = ({
|
||||||
tickets,
|
tickets,
|
||||||
allProjects,
|
allProjects,
|
||||||
addButton = true,
|
addButton = true,
|
||||||
|
|
@ -59,6 +58,14 @@ export const TicketList: FC<TicketListProps> = ({
|
||||||
t.title.toLowerCase().includes(filterText.toLowerCase())
|
t.title.toLowerCase().includes(filterText.toLowerCase())
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const { getTokenSilently } = useAuth0();
|
||||||
|
|
||||||
|
const handleValidate = async (id: number) => {
|
||||||
|
const token = await getTokenSilently();
|
||||||
|
const Tickets = new TicketService(token);
|
||||||
|
await Tickets.close(id.toString());
|
||||||
|
};
|
||||||
|
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -99,28 +106,24 @@ export const TicketList: FC<TicketListProps> = ({
|
||||||
/>
|
/>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={12}>
|
<Grid item xs={12}>
|
||||||
<div className="col s12 grey lighten-1">
|
{filteredTickets.length === 0 ? (
|
||||||
{filteredTickets.length === 0 ? (
|
<TicketCard />
|
||||||
<TicketCard />
|
) : (
|
||||||
) : (
|
filteredTickets.map((t: Ticket) => (
|
||||||
filteredTickets.map((t: Ticket) => (
|
<TicketCard
|
||||||
<TicketCard
|
key={t.id}
|
||||||
key={t.id}
|
ticket={t}
|
||||||
ticket={t}
|
link={`/tickets/${t.id}`}
|
||||||
link={`/tickets/${t.id}`}
|
validateTicket={() => {
|
||||||
validateTicket={async (e: MouseEvent) => {
|
handleValidate(t.id);
|
||||||
e.preventDefault();
|
}}
|
||||||
await put<HttpResponse<Ticket>>(
|
/>
|
||||||
`${Constants.ticketsURI}/${t.id}/closed`,
|
))
|
||||||
{}
|
)}
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
))
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default TicketList;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import React, { FC } from "react";
|
import React, { FC } from "react";
|
||||||
import { InputField } from "./InputField";
|
import InputField from "./InputField";
|
||||||
import { PasswordField } from "./PasswordField";
|
import PasswordField from "./PasswordField";
|
||||||
import { Button } from "./Buttons/Button";
|
import Button from "./Buttons/Button";
|
||||||
|
|
||||||
export const LogInForm: FC = () => {
|
export const LogInForm: FC = () => {
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import React, { FC } from "react";
|
import React, { FC } from "react";
|
||||||
import Dialog from "@material-ui/core/Dialog";
|
|
||||||
import {
|
import {
|
||||||
|
Dialog,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
Typography,
|
Typography,
|
||||||
IconButton,
|
IconButton,
|
||||||
|
|
@ -36,7 +36,7 @@ const useStyles = makeStyles((theme: Theme) =>
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
export const Modal: FC<IProps> = ({
|
const Modal: FC<IProps> = ({
|
||||||
handleClose,
|
handleClose,
|
||||||
show,
|
show,
|
||||||
action,
|
action,
|
||||||
|
|
@ -77,3 +77,5 @@ export const Modal: FC<IProps> = ({
|
||||||
</Dialog>
|
</Dialog>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default Modal;
|
||||||
|
|
|
||||||
|
|
@ -1,36 +1,48 @@
|
||||||
import React, { FC, useState, FormEvent } from "react";
|
import React, { FC, useState, FormEvent } from "react";
|
||||||
import { TextField } from "@material-ui/core";
|
import { TextField } from "@material-ui/core";
|
||||||
import { Modal } from "./Modal";
|
import Modal from "./Modal";
|
||||||
import { Project } from "../../types/Project";
|
import Preloader from "../Preloader";
|
||||||
import { User } from "../../types/User";
|
import { useAuth0 } from "../../authentication/auth0";
|
||||||
import { post } from "../../utils/http";
|
import { ProjectService } from "../../services";
|
||||||
import { Constants } from "../../utils/Constants";
|
import { getUID } from "../../authentication/helpers";
|
||||||
|
import { today } from "../../utils/methods";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
show: boolean;
|
show: boolean;
|
||||||
handleClose: () => void;
|
handleClose: () => void;
|
||||||
allUsers: User[];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const NewProjectModal: FC<IProps> = ({ show, handleClose }) => {
|
const NewProjectModal: FC<IProps> = ({ show, handleClose }) => {
|
||||||
const [title, setTitle] = useState("");
|
const [title, setTitle] = useState("");
|
||||||
const [description, setDescription] = useState("");
|
const [description, setDescription] = useState("");
|
||||||
const [endingDate, setEndingDate] = useState("");
|
const [endingDate, setEndingDate] = useState(today());
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
const { getTokenSilently, user } = useAuth0();
|
||||||
|
|
||||||
const handleSubmit = async (e: FormEvent) => {
|
const handleSubmit = async (e: FormEvent) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
setLoading(true);
|
||||||
let newProject = {
|
let newProject = {
|
||||||
title: title,
|
title: title,
|
||||||
description: description,
|
description: description,
|
||||||
endingDate: new Date(endingDate).toISOString(),
|
endingDate: new Date(endingDate).toISOString(),
|
||||||
managerId: "cd179eb7-3a54-4060-b22c-3e947bdffcbc", // get current User id
|
managerId: getUID(user),
|
||||||
};
|
};
|
||||||
|
|
||||||
await post<Project>(`${Constants.projectsURI}`, newProject);
|
const token = await getTokenSilently();
|
||||||
|
const Projects = new ProjectService(token);
|
||||||
|
Projects.add(newProject).catch((err) => console.error(err));
|
||||||
|
setLoading(false);
|
||||||
|
setTitle("");
|
||||||
|
setDescription("");
|
||||||
|
setEndingDate(today());
|
||||||
|
|
||||||
handleClose();
|
handleClose();
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return loading ? (
|
||||||
|
<Preloader />
|
||||||
|
) : (
|
||||||
<Modal
|
<Modal
|
||||||
name="New Project"
|
name="New Project"
|
||||||
show={show}
|
show={show}
|
||||||
|
|
@ -88,3 +100,5 @@ export const NewProjectModal: FC<IProps> = ({ show, handleClose }) => {
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default NewProjectModal;
|
||||||
|
|
|
||||||
|
|
@ -7,14 +7,16 @@ import {
|
||||||
makeStyles,
|
makeStyles,
|
||||||
Theme,
|
Theme,
|
||||||
} from "@material-ui/core";
|
} from "@material-ui/core";
|
||||||
import { Modal } from "./Modal";
|
import Modal from "./Modal";
|
||||||
import { Ticket } from "../../types/Ticket";
|
import Project from "../../types/Project";
|
||||||
import { Project } from "../../types/Project";
|
|
||||||
import { post } from "../../utils/http";
|
|
||||||
import { Constants } from "../../utils/Constants";
|
|
||||||
import Category from "../../types/enums/category";
|
import Category from "../../types/enums/category";
|
||||||
import Impact from "../../types/enums/impact";
|
import Impact from "../../types/enums/impact";
|
||||||
import Difficulty from "../../types/enums/difficulty";
|
import Difficulty from "../../types/enums/difficulty";
|
||||||
|
import { TicketService } from "../../services";
|
||||||
|
import { useAuth0 } from "../../authentication/auth0";
|
||||||
|
import { getUID } from "../../authentication/helpers";
|
||||||
|
import { today } from "../../utils/methods";
|
||||||
|
import Preloader from "../Preloader";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
show: boolean;
|
show: boolean;
|
||||||
|
|
@ -28,42 +30,50 @@ const useStyles = makeStyles((theme: Theme) => ({
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const NewTicketModal: FC<IProps> = ({
|
const NewTicketModal: FC<IProps> = ({ show, handleClose, allProjects }) => {
|
||||||
show,
|
const { getTokenSilently, user } = useAuth0();
|
||||||
handleClose,
|
|
||||||
allProjects,
|
|
||||||
}) => {
|
|
||||||
const [title, setTitle] = useState("");
|
|
||||||
const [description, setDescription] = useState("");
|
|
||||||
const [endingDate, setEndingDate] = useState("");
|
|
||||||
|
|
||||||
const { url } = useRouteMatch();
|
const { url } = useRouteMatch();
|
||||||
const id = url.split("/")[2];
|
const id = url.split("/")[2];
|
||||||
const [projectId, setProjectId] = useState(id);
|
const [projectId, setProjectId] = useState(id);
|
||||||
const [categoryID, setCategoryID] = useState(0);
|
const [title, setTitle] = useState("");
|
||||||
const [impactID, setImpactID] = useState(0);
|
const [description, setDescription] = useState("");
|
||||||
const [difficultyID, setDifficultyID] = useState(0);
|
const [endingDate, setEndingDate] = useState(today());
|
||||||
|
const [categoryID, setCategoryID] = useState(1);
|
||||||
|
const [impactID, setImpactID] = useState(1);
|
||||||
|
const [difficultyID, setDifficultyID] = useState(1);
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
const handleSubmit = async (e: FormEvent) => {
|
const handleSubmit = async (e: FormEvent) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
setLoading(true);
|
||||||
let newTicket = {
|
let newTicket = {
|
||||||
title: title,
|
title: title,
|
||||||
description: description,
|
description: description,
|
||||||
endingDate: new Date(endingDate).toISOString(),
|
endingDate: new Date(endingDate).toISOString(),
|
||||||
creatorId: "20bf4b2a-7209-4826-96cd-29c2bc937a94", // get current User id
|
creatorId: getUID(user),
|
||||||
projectId: parseInt(projectId),
|
projectId: parseInt(projectId),
|
||||||
impact: impactID,
|
impact: impactID,
|
||||||
difficulty: difficultyID,
|
difficulty: difficultyID,
|
||||||
category: categoryID,
|
category: categoryID,
|
||||||
};
|
};
|
||||||
|
|
||||||
// const response: HttpResponse<Ticket> =
|
const token = await getTokenSilently();
|
||||||
await post<Ticket>(`${Constants.ticketsURI}`, newTicket);
|
const Tickets = new TicketService(token);
|
||||||
|
Tickets.add(newTicket).catch((err) => console.error(err));
|
||||||
|
setLoading(false);
|
||||||
|
setTitle("");
|
||||||
|
setDescription("");
|
||||||
|
setEndingDate(today());
|
||||||
|
setCategoryID(1);
|
||||||
|
setImpactID(1);
|
||||||
|
setDifficultyID(1);
|
||||||
handleClose();
|
handleClose();
|
||||||
};
|
};
|
||||||
|
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
return (
|
return loading ? (
|
||||||
|
<Preloader />
|
||||||
|
) : (
|
||||||
<Modal
|
<Modal
|
||||||
name="New Ticket"
|
name="New Ticket"
|
||||||
show={show}
|
show={show}
|
||||||
|
|
@ -160,7 +170,7 @@ export const NewTicketModal: FC<IProps> = ({
|
||||||
className={classes.select}
|
className={classes.select}
|
||||||
>
|
>
|
||||||
{Category.map((c: string, i: number) => (
|
{Category.map((c: string, i: number) => (
|
||||||
<MenuItem key={i} value={i}>
|
<MenuItem key={i} value={i + 1}>
|
||||||
{c}
|
{c}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
))}
|
))}
|
||||||
|
|
@ -181,7 +191,7 @@ export const NewTicketModal: FC<IProps> = ({
|
||||||
margin="normal"
|
margin="normal"
|
||||||
>
|
>
|
||||||
{Impact.map((c: string, i: number) => (
|
{Impact.map((c: string, i: number) => (
|
||||||
<MenuItem key={i} value={i}>
|
<MenuItem key={i} value={i + 1}>
|
||||||
{c}
|
{c}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
))}
|
))}
|
||||||
|
|
@ -202,7 +212,7 @@ export const NewTicketModal: FC<IProps> = ({
|
||||||
margin="normal"
|
margin="normal"
|
||||||
>
|
>
|
||||||
{Difficulty.map((c: string, i: number) => (
|
{Difficulty.map((c: string, i: number) => (
|
||||||
<MenuItem key={i} value={i}>
|
<MenuItem key={i} value={i + 1}>
|
||||||
{c}
|
{c}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
))}
|
))}
|
||||||
|
|
@ -211,3 +221,5 @@ export const NewTicketModal: FC<IProps> = ({
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default NewTicketModal;
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,22 @@
|
||||||
import React, { FC, useState, ChangeEvent, FormEvent } from "react";
|
import React, { FC, useState, ChangeEvent, FormEvent } from "react";
|
||||||
import { useParams } from "react-router-dom";
|
import { useParams } from "react-router-dom";
|
||||||
import { Grid } from "@material-ui/core";
|
import {
|
||||||
|
Avatar,
|
||||||
|
Checkbox,
|
||||||
|
Grid,
|
||||||
|
List,
|
||||||
|
ListItem,
|
||||||
|
ListItemSecondaryAction,
|
||||||
|
ListItemText,
|
||||||
|
ListItemAvatar,
|
||||||
|
} from "@material-ui/core";
|
||||||
import { createStyles, makeStyles, Theme } from "@material-ui/core/styles";
|
import { createStyles, makeStyles, Theme } from "@material-ui/core/styles";
|
||||||
import List from "@material-ui/core/List";
|
import AvatarList from "../Avatars/AvatarList";
|
||||||
import ListItem from "@material-ui/core/ListItem";
|
import FilterBar from "../FilterBar";
|
||||||
import ListItemSecondaryAction from "@material-ui/core/ListItemSecondaryAction";
|
import Modal from "./Modal";
|
||||||
import ListItemText from "@material-ui/core/ListItemText";
|
import User from "../../types/User";
|
||||||
import ListItemAvatar from "@material-ui/core/ListItemAvatar";
|
import { ProjectService } from "../../services";
|
||||||
import Checkbox from "@material-ui/core/Checkbox";
|
import { useAuth0 } from "../../authentication/auth0";
|
||||||
import Avatar from "@material-ui/core/Avatar";
|
|
||||||
import { Modal } from "./Modal";
|
|
||||||
import { AvatarList } from "../Avatars/AvatarList";
|
|
||||||
import { FilterBar } from "../FilterBar";
|
|
||||||
import { User } from "../../types/User";
|
|
||||||
import { patch } from "../../utils/http";
|
|
||||||
import { Constants } from "../../utils/Constants";
|
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
show: boolean;
|
show: boolean;
|
||||||
|
|
@ -33,12 +35,7 @@ const useStyles = makeStyles((theme: Theme) =>
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
export const UsersModal: FC<IProps> = ({
|
const UsersModal: FC<IProps> = ({ show, handleClose, users, allUsers }) => {
|
||||||
show,
|
|
||||||
handleClose,
|
|
||||||
users,
|
|
||||||
allUsers,
|
|
||||||
}) => {
|
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
|
|
||||||
const [filterText, setFilterText] = useState<string>("");
|
const [filterText, setFilterText] = useState<string>("");
|
||||||
|
|
@ -62,12 +59,14 @@ export const UsersModal: FC<IProps> = ({
|
||||||
setMembers(newChecked);
|
setMembers(newChecked);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const { getTokenSilently } = useAuth0();
|
||||||
const handleSubmit = async (e: FormEvent) => {
|
const handleSubmit = async (e: FormEvent) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
await patch<User[]>(
|
if (id !== undefined) {
|
||||||
`${Constants.projectsURI}/${id}/members`,
|
const token = await getTokenSilently();
|
||||||
members //.map((m) => m.id)
|
const Projects = new ProjectService(token);
|
||||||
);
|
await Projects.setMembers(id, members);
|
||||||
|
}
|
||||||
handleClose();
|
handleClose();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -112,3 +111,5 @@ export const UsersModal: FC<IProps> = ({
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default UsersModal;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import React, { FC } from "react";
|
import React, { FC } from "react";
|
||||||
import { User } from "../../types/User";
|
import User from "../../types/User";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
setMembers: React.Dispatch<React.SetStateAction<User[]>>;
|
setMembers: React.Dispatch<React.SetStateAction<User[]>>;
|
||||||
|
|
@ -7,7 +7,7 @@ interface IProps {
|
||||||
user: User;
|
user: User;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const UsersModalEntry: FC<IProps> = ({ user, setMembers, members }) => {
|
const UsersModalEntry: FC<IProps> = ({ user, setMembers, members }) => {
|
||||||
const match: (id: string) => boolean = (id: string) => {
|
const match: (id: string) => boolean = (id: string) => {
|
||||||
return Boolean(members.find((m) => m.id === id));
|
return Boolean(members.find((m) => m.id === id));
|
||||||
};
|
};
|
||||||
|
|
@ -40,3 +40,5 @@ export const UsersModalEntry: FC<IProps> = ({ user, setMembers, members }) => {
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default UsersModalEntry;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useAuth0 } from "../authentication/auth0";
|
import { useAuth0 } from "../authentication/auth0";
|
||||||
|
|
||||||
export const NavBar = () => {
|
const NavBar = () => {
|
||||||
const { isAuthenticated, loginWithRedirect, logout } = useAuth0();
|
const { isAuthenticated, loginWithRedirect, logout } = useAuth0();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -14,3 +14,5 @@ export const NavBar = () => {
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default NavBar;
|
||||||
|
|
|
||||||
|
|
@ -1,67 +0,0 @@
|
||||||
import React, { FC } from "react";
|
|
||||||
import { TextField, MenuItem } from "@material-ui/core";
|
|
||||||
import { Project } from "../types/Project";
|
|
||||||
|
|
||||||
interface IProps {
|
|
||||||
title: string;
|
|
||||||
setTitle: React.Dispatch<React.SetStateAction<string>>;
|
|
||||||
description: string;
|
|
||||||
setDescription: React.Dispatch<React.SetStateAction<string>>;
|
|
||||||
endingDate: string;
|
|
||||||
setEndingDate: React.Dispatch<React.SetStateAction<string>>;
|
|
||||||
allProjects: Project[];
|
|
||||||
projectId: string;
|
|
||||||
setProjectId: React.Dispatch<React.SetStateAction<string>>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const NewTicketForm: FC<IProps> = ({
|
|
||||||
title,
|
|
||||||
setTitle,
|
|
||||||
description,
|
|
||||||
setDescription,
|
|
||||||
endingDate,
|
|
||||||
setEndingDate,
|
|
||||||
allProjects,
|
|
||||||
projectId,
|
|
||||||
setProjectId,
|
|
||||||
}) => {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{/* <div className="row">
|
|
||||||
<div className="input-field">
|
|
||||||
<i className="material-icons prefix">date_range</i>
|
|
||||||
<input
|
|
||||||
id="Due Date"
|
|
||||||
type="text"
|
|
||||||
className="datepicker"
|
|
||||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
|
||||||
setEndingDate(e.target.value)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<label htmlFor="Due Date">Due Date</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="input-field">
|
|
||||||
<select
|
|
||||||
id="project"
|
|
||||||
className="browser-default"
|
|
||||||
value={projectId}
|
|
||||||
onChange={(e: React.ChangeEvent<HTMLSelectElement>) => {
|
|
||||||
e.preventDefault();
|
|
||||||
setProjectId(e.target.value);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<option value={0} disabled>
|
|
||||||
Project
|
|
||||||
</option>
|
|
||||||
{allProjects.map((p) => (
|
|
||||||
<option key={p.id} value={p.id}>
|
|
||||||
{p.title}
|
|
||||||
</option>
|
|
||||||
))}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div> */}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
@ -1,16 +1,11 @@
|
||||||
import React, { FC, useState, ReactNode } from "react";
|
import React, { FC, useState, ReactNode } from "react";
|
||||||
import { makeStyles, Theme, useTheme } from "@material-ui/core/styles";
|
|
||||||
import AppBar from "@material-ui/core/AppBar";
|
|
||||||
import Tabs from "@material-ui/core/Tabs";
|
|
||||||
import Tab from "@material-ui/core/Tab";
|
|
||||||
import Typography from "@material-ui/core/Typography";
|
|
||||||
import Box from "@material-ui/core/Box";
|
|
||||||
import SwipeableViews from "react-swipeable-views";
|
import SwipeableViews from "react-swipeable-views";
|
||||||
import { Ticket } from "../../types/Ticket";
|
import { makeStyles, Theme, useTheme } from "@material-ui/core/styles";
|
||||||
import { Project } from "../../types/Project";
|
import { AppBar, Box, Tab, Tabs, Typography } from "@material-ui/core";
|
||||||
import { TicketList } from "../Lists/TicketList";
|
import Ticket from "../../types/Ticket";
|
||||||
// import { FileList } from "./AppFileList";
|
import Project from "../../types/Project";
|
||||||
import { AppFile } from "../../types/AppFile";
|
import TicketList from "../Lists/TicketList";
|
||||||
|
import AppFile from "../../types/AppFile";
|
||||||
|
|
||||||
interface TabProps {
|
interface TabProps {
|
||||||
children?: ReactNode;
|
children?: ReactNode;
|
||||||
|
|
@ -59,7 +54,7 @@ interface IProps {
|
||||||
allProjects: Project[];
|
allProjects: Project[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ProjectTabPanel: FC<IProps> = ({
|
const ProjectTabPanel: FC<IProps> = ({
|
||||||
tickets,
|
tickets,
|
||||||
tabNames,
|
tabNames,
|
||||||
files,
|
files,
|
||||||
|
|
@ -116,3 +111,5 @@ export const ProjectTabPanel: FC<IProps> = ({
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default ProjectTabPanel;
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
import React, { FC } from "react";
|
import React, { FC } from "react";
|
||||||
import { Route, useRouteMatch, Redirect } from "react-router-dom";
|
import { Route, useRouteMatch, Redirect } from "react-router-dom";
|
||||||
import { TabRouterHeader } from "./TabRouterHeader";
|
import TabRouterHeader from "./TabRouterHeader";
|
||||||
import { TicketList } from "../Lists/TicketList";
|
import TicketList from "../Lists/TicketList";
|
||||||
import { FileList } from "../Lists/AppFileList";
|
import FileList from "../Lists/AppFileList";
|
||||||
import { Ticket } from "../../types/Ticket";
|
import Ticket from "../../types/Ticket";
|
||||||
import { AppFile } from "../../types/AppFile";
|
import AppFile from "../../types/AppFile";
|
||||||
import { Activity } from "../../types/Activity";
|
import Activity from "../../types/Activity";
|
||||||
import { Project } from "../../types/Project";
|
import Project from "../../types/Project";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
tickets: Ticket[];
|
tickets: Ticket[];
|
||||||
|
|
@ -17,7 +17,7 @@ interface IProps {
|
||||||
allProjects: Project[];
|
allProjects: Project[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const TabRouter: FC<IProps> = ({
|
const TabRouter: FC<IProps> = ({
|
||||||
tickets,
|
tickets,
|
||||||
tabNames,
|
tabNames,
|
||||||
files,
|
files,
|
||||||
|
|
@ -48,3 +48,5 @@ export const TabRouter: FC<IProps> = ({
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default TabRouter;
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,9 @@ interface IProps {
|
||||||
tabNames: string[];
|
tabNames: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const TabRouterHeader: FC<IProps> = ({
|
const TabRouterHeader: FC<IProps> = ({
|
||||||
tabNames,
|
tabNames,
|
||||||
tabClass = `tab col s${12 / tabNames.length}`
|
tabClass = `tab col s${12 / tabNames.length}`,
|
||||||
}) => {
|
}) => {
|
||||||
const [isActive, setIsActive] = useState(0);
|
const [isActive, setIsActive] = useState(0);
|
||||||
const nTabs = tabNames.length;
|
const nTabs = tabNames.length;
|
||||||
|
|
@ -31,7 +31,7 @@ export const TabRouterHeader: FC<IProps> = ({
|
||||||
className="indicator indigo lighten-2"
|
className="indicator indigo lighten-2"
|
||||||
style={{
|
style={{
|
||||||
left: `${(isActive / nTabs) * 100}%`,
|
left: `${(isActive / nTabs) * 100}%`,
|
||||||
right: `${(1 - (isActive + 1) / nTabs) * 100}%`
|
right: `${(1 - (isActive + 1) / nTabs) * 100}%`,
|
||||||
}}
|
}}
|
||||||
></li>
|
></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
@ -54,7 +54,7 @@ const TabUnit: FC<TabUnitProps> = ({
|
||||||
setIsActive,
|
setIsActive,
|
||||||
text,
|
text,
|
||||||
value,
|
value,
|
||||||
nTabs
|
nTabs,
|
||||||
}) => {
|
}) => {
|
||||||
const { url } = useRouteMatch();
|
const { url } = useRouteMatch();
|
||||||
return (
|
return (
|
||||||
|
|
@ -63,7 +63,7 @@ const TabUnit: FC<TabUnitProps> = ({
|
||||||
key={value}
|
key={value}
|
||||||
style={{
|
style={{
|
||||||
left: `${(isActive / nTabs) * 100}%`,
|
left: `${(isActive / nTabs) * 100}%`,
|
||||||
right: `${(1 - (isActive + 1) / nTabs) * 100}%`
|
right: `${(1 - (isActive + 1) / nTabs) * 100}%`,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Link
|
<Link
|
||||||
|
|
@ -81,3 +81,5 @@ const TabUnit: FC<TabUnitProps> = ({
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default TabRouterHeader;
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,11 @@
|
||||||
import React, { FC, useState, ReactNode } from "react";
|
import React, { FC, useState, ReactNode } from "react";
|
||||||
import SwipeableViews from "react-swipeable-views";
|
import SwipeableViews from "react-swipeable-views";
|
||||||
import { makeStyles, Theme, useTheme } from "@material-ui/core/styles";
|
import { makeStyles, Theme, useTheme } from "@material-ui/core/styles";
|
||||||
import AppBar from "@material-ui/core/AppBar";
|
import { AppBar, Box, Tab, Tabs, Typography } from "@material-ui/core";
|
||||||
import Tabs from "@material-ui/core/Tabs";
|
import ProjectList from "../Lists/ProjectList";
|
||||||
import Tab from "@material-ui/core/Tab";
|
import TicketList from "../Lists/TicketList";
|
||||||
import Typography from "@material-ui/core/Typography";
|
import Ticket from "../../types/Ticket";
|
||||||
import Box from "@material-ui/core/Box";
|
import Project from "../../types/Project";
|
||||||
import { Ticket } from "../../types/Ticket";
|
|
||||||
import { Project } from "../../types/Project";
|
|
||||||
import { ProjectList } from "../Lists/ProjectList";
|
|
||||||
import { TicketList } from "../Lists/TicketList";
|
|
||||||
import { User } from "../../types/User";
|
|
||||||
|
|
||||||
interface TabProps {
|
interface TabProps {
|
||||||
children?: ReactNode;
|
children?: ReactNode;
|
||||||
|
|
@ -55,15 +50,9 @@ interface IProps {
|
||||||
tabNames: string[];
|
tabNames: string[];
|
||||||
tickets: Ticket[];
|
tickets: Ticket[];
|
||||||
projects: Project[];
|
projects: Project[];
|
||||||
allUsers: User[];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const UserTabPanel: FC<IProps> = ({
|
const UserTabPanel: FC<IProps> = ({ tickets, tabNames, projects }) => {
|
||||||
tickets,
|
|
||||||
tabNames,
|
|
||||||
projects,
|
|
||||||
allUsers,
|
|
||||||
}) => {
|
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const [value, setValue] = useState(0);
|
const [value, setValue] = useState(0);
|
||||||
|
|
@ -98,7 +87,7 @@ export const UserTabPanel: FC<IProps> = ({
|
||||||
onChangeIndex={handleChangeIndex}
|
onChangeIndex={handleChangeIndex}
|
||||||
>
|
>
|
||||||
<TabPanel value={value} index={0} dir={theme.direction}>
|
<TabPanel value={value} index={0} dir={theme.direction}>
|
||||||
<ProjectList projects={projects} allUsers={allUsers} />
|
<ProjectList projects={projects} />
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
<TabPanel value={value} index={1} dir={theme.direction}>
|
<TabPanel value={value} index={1} dir={theme.direction}>
|
||||||
<TicketList tickets={tickets} allProjects={[]} addButton={false} />
|
<TicketList tickets={tickets} allProjects={[]} addButton={false} />
|
||||||
|
|
@ -107,3 +96,4 @@ export const UserTabPanel: FC<IProps> = ({
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
export default UserTabPanel;
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,9 @@
|
||||||
import React, { FC } from "react";
|
import React, { FC } from "react";
|
||||||
import { Route, useRouteMatch, Redirect } from "react-router-dom";
|
import { Route, useRouteMatch, Redirect } from "react-router-dom";
|
||||||
import { TabRouterHeader } from "./TabRouterHeader";
|
import TabRouterHeader from "./TabRouterHeader";
|
||||||
import { ProjectList } from "../Lists/ProjectList";
|
import TicketList from "../Lists/TicketList";
|
||||||
import { Ticket } from "../../types/Ticket";
|
import Ticket from "../../types/Ticket";
|
||||||
import { Project } from "../../types/Project";
|
import Project from "../../types/Project";
|
||||||
import { TicketList } from "../Lists/TicketList";
|
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
tabNames: string[];
|
tabNames: string[];
|
||||||
|
|
@ -33,3 +32,5 @@ export const UserTabRouter: FC<IProps> = ({ tickets, tabNames, projects }) => {
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default UserTabRouter;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import React, { FC } from "react";
|
import React, { FC } from "react";
|
||||||
|
|
||||||
export const PasswordField: FC = () => {
|
const PasswordField: FC = () => {
|
||||||
return (
|
return (
|
||||||
<div className="input-field">
|
<div className="input-field">
|
||||||
<input id="password" type="password" className="validate" />
|
<input id="password" type="password" className="validate" />
|
||||||
|
|
@ -8,3 +8,5 @@ export const PasswordField: FC = () => {
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default PasswordField;
|
||||||
|
|
|
||||||
|
|
@ -1,55 +1,24 @@
|
||||||
import React, { FC } from "react";
|
import React, { FC } from "react";
|
||||||
|
import { Backdrop, CircularProgress } from "@material-ui/core";
|
||||||
|
import { makeStyles, createStyles, Theme } from "@material-ui/core/styles";
|
||||||
|
|
||||||
|
const useStyles = makeStyles((theme: Theme) =>
|
||||||
|
createStyles({
|
||||||
|
backdrop: {
|
||||||
|
zIndex: theme.zIndex.drawer + 1,
|
||||||
|
color: "#fff",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
const Preloader: FC = () => {
|
||||||
|
const classes = useStyles();
|
||||||
|
|
||||||
export const Preloader: FC = () => {
|
|
||||||
return (
|
return (
|
||||||
<div className="preloader-wrapper big active">
|
<Backdrop className={classes.backdrop} open={true}>
|
||||||
<div className="spinner-layer spinner-blue">
|
<CircularProgress color="inherit" />
|
||||||
<div className="circle-clipper left">
|
</Backdrop>
|
||||||
<div className="circle"></div>
|
|
||||||
</div>
|
|
||||||
<div className="gap-patch">
|
|
||||||
<div className="circle"></div>
|
|
||||||
</div>
|
|
||||||
<div className="circle-clipper right">
|
|
||||||
<div className="circle"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="spinner-layer spinner-red">
|
|
||||||
<div className="circle-clipper left">
|
|
||||||
<div className="circle"></div>
|
|
||||||
</div>
|
|
||||||
<div className="gap-patch">
|
|
||||||
<div className="circle"></div>
|
|
||||||
</div>
|
|
||||||
<div className="circle-clipper right">
|
|
||||||
<div className="circle"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="spinner-layer spinner-yellow">
|
|
||||||
<div className="circle-clipper left">
|
|
||||||
<div className="circle"></div>
|
|
||||||
</div>
|
|
||||||
<div className="gap-patch">
|
|
||||||
<div className="circle"></div>
|
|
||||||
</div>
|
|
||||||
<div className="circle-clipper right">
|
|
||||||
<div className="circle"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="spinner-layer spinner-green">
|
|
||||||
<div className="circle-clipper left">
|
|
||||||
<div className="circle"></div>
|
|
||||||
</div>
|
|
||||||
<div className="gap-patch">
|
|
||||||
<div className="circle"></div>
|
|
||||||
</div>
|
|
||||||
<div className="circle-clipper right">
|
|
||||||
<div className="circle"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default Preloader;
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import React, { FC } from "react";
|
import React, { FC } from "react";
|
||||||
import { UserAvatar } from "./Avatars/UserAvatar";
|
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
|
import { UserAvatar } from "./Avatars/UserAvatar";
|
||||||
|
|
||||||
export const ProfileSelector: FC = () => {
|
const ProfileSelector: FC = () => {
|
||||||
return (
|
return (
|
||||||
<div className="section col s10 offset-s1 white z-depth-1">
|
<div className="section col s10 offset-s1 white z-depth-1">
|
||||||
<div className="row ">
|
<div className="row ">
|
||||||
|
|
@ -20,3 +20,4 @@ export const ProfileSelector: FC = () => {
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
export default ProfileSelector;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
import React, { FC } from "react";
|
import React, { FC } from "react";
|
||||||
|
import { Box, LinearProgress } from "@material-ui/core";
|
||||||
import { makeStyles, Theme, createStyles } from "@material-ui/core/styles";
|
import { makeStyles, Theme, createStyles } from "@material-ui/core/styles";
|
||||||
import LinearProgress from "@material-ui/core/LinearProgress";
|
|
||||||
import { Box } from "@material-ui/core";
|
|
||||||
|
|
||||||
type IProps = {
|
type IProps = {
|
||||||
value: number;
|
value: number;
|
||||||
|
|
@ -18,7 +17,7 @@ const useStyles = makeStyles((theme: Theme) =>
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
export const ProgressBar: FC<IProps> = ({ value }) => {
|
const ProgressBar: FC<IProps> = ({ value }) => {
|
||||||
// const styleString: CSSProperties = { width: `${value}%` };
|
// const styleString: CSSProperties = { width: `${value}%` };
|
||||||
// let barColor: string = "green";
|
// let barColor: string = "green";
|
||||||
|
|
||||||
|
|
@ -43,3 +42,5 @@ export const ProgressBar: FC<IProps> = ({ value }) => {
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default ProgressBar;
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ type IProps = {
|
||||||
// })
|
// })
|
||||||
// );
|
// );
|
||||||
|
|
||||||
export const ProgressInfo: FC<IProps> = ({
|
const ProgressInfo: FC<IProps> = ({
|
||||||
tasksDone,
|
tasksDone,
|
||||||
tasksTotalCount,
|
tasksTotalCount,
|
||||||
remainingDays,
|
remainingDays,
|
||||||
|
|
@ -39,3 +39,5 @@ export const ProgressInfo: FC<IProps> = ({
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default ProgressInfo;
|
||||||
|
|
|
||||||
|
|
@ -2,20 +2,17 @@ import React from "react";
|
||||||
import Avatar from "@material-ui/core/Avatar";
|
import Avatar from "@material-ui/core/Avatar";
|
||||||
import Button from "@material-ui/core/Button";
|
import Button from "@material-ui/core/Button";
|
||||||
import CssBaseline from "@material-ui/core/CssBaseline";
|
import CssBaseline from "@material-ui/core/CssBaseline";
|
||||||
import TextField from "@material-ui/core/TextField";
|
|
||||||
import FormControlLabel from "@material-ui/core/FormControlLabel";
|
|
||||||
import Checkbox from "@material-ui/core/Checkbox";
|
|
||||||
import Link from "@material-ui/core/Link";
|
|
||||||
import Paper from "@material-ui/core/Paper";
|
import Paper from "@material-ui/core/Paper";
|
||||||
import Grid from "@material-ui/core/Grid";
|
import Grid from "@material-ui/core/Grid";
|
||||||
import LockOutlinedIcon from "@material-ui/icons/LockOutlined";
|
import LockOutlinedIcon from "@material-ui/icons/LockOutlined";
|
||||||
import Typography from "@material-ui/core/Typography";
|
import Typography from "@material-ui/core/Typography";
|
||||||
import { makeStyles, createStyles, Theme } from "@material-ui/core/styles";
|
import { makeStyles, createStyles, Theme } from "@material-ui/core/styles";
|
||||||
|
import { useAuth0 } from "../authentication/auth0";
|
||||||
|
|
||||||
const useStyles = makeStyles((theme: Theme) =>
|
const useStyles = makeStyles((theme: Theme) =>
|
||||||
createStyles({
|
createStyles({
|
||||||
root: {
|
root: {
|
||||||
height: "100vh"
|
height: "100vh",
|
||||||
},
|
},
|
||||||
image: {
|
image: {
|
||||||
backgroundImage: "url(https://source.unsplash.com/daily?dev)",
|
backgroundImage: "url(https://source.unsplash.com/daily?dev)",
|
||||||
|
|
@ -25,30 +22,31 @@ const useStyles = makeStyles((theme: Theme) =>
|
||||||
? theme.palette.grey[50]
|
? theme.palette.grey[50]
|
||||||
: theme.palette.grey[900],
|
: theme.palette.grey[900],
|
||||||
backgroundSize: "cover",
|
backgroundSize: "cover",
|
||||||
backgroundPosition: "center"
|
backgroundPosition: "center",
|
||||||
},
|
},
|
||||||
paper: {
|
paper: {
|
||||||
margin: theme.spacing(8, 4),
|
margin: theme.spacing(8, 4),
|
||||||
display: "flex",
|
display: "flex",
|
||||||
flexDirection: "column",
|
flexDirection: "column",
|
||||||
alignItems: "center"
|
alignItems: "center",
|
||||||
},
|
},
|
||||||
avatar: {
|
avatar: {
|
||||||
margin: theme.spacing(1),
|
margin: theme.spacing(1),
|
||||||
backgroundColor: theme.palette.secondary.main
|
backgroundColor: theme.palette.secondary.main,
|
||||||
},
|
},
|
||||||
form: {
|
form: {
|
||||||
width: "100%",
|
width: "100%",
|
||||||
marginTop: theme.spacing(1)
|
marginTop: theme.spacing(1),
|
||||||
},
|
},
|
||||||
submit: {
|
submit: {
|
||||||
margin: theme.spacing(3, 0, 2)
|
margin: theme.spacing(3, 0, 2),
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
export default function SignInSide() {
|
export default function SignInSide() {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
|
const { loginWithRedirect } = useAuth0();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid container component="main" className={classes.root}>
|
<Grid container component="main" className={classes.root}>
|
||||||
|
|
@ -63,53 +61,16 @@ export default function SignInSide() {
|
||||||
Sign in
|
Sign in
|
||||||
</Typography>
|
</Typography>
|
||||||
<form className={classes.form} noValidate>
|
<form className={classes.form} noValidate>
|
||||||
<TextField
|
|
||||||
variant="outlined"
|
|
||||||
margin="normal"
|
|
||||||
required
|
|
||||||
fullWidth
|
|
||||||
id="email"
|
|
||||||
label="Email Address"
|
|
||||||
name="email"
|
|
||||||
autoComplete="email"
|
|
||||||
autoFocus
|
|
||||||
/>
|
|
||||||
<TextField
|
|
||||||
variant="outlined"
|
|
||||||
margin="normal"
|
|
||||||
required
|
|
||||||
fullWidth
|
|
||||||
name="password"
|
|
||||||
label="Password"
|
|
||||||
type="password"
|
|
||||||
id="password"
|
|
||||||
autoComplete="current-password"
|
|
||||||
/>
|
|
||||||
<FormControlLabel
|
|
||||||
control={<Checkbox value="remember" color="primary" />}
|
|
||||||
label="Remember me"
|
|
||||||
/>
|
|
||||||
<Button
|
<Button
|
||||||
type="submit"
|
type="submit"
|
||||||
fullWidth
|
fullWidth
|
||||||
variant="contained"
|
variant="contained"
|
||||||
color="primary"
|
color="primary"
|
||||||
className={classes.submit}
|
className={classes.submit}
|
||||||
|
onClick={() => loginWithRedirect({})}
|
||||||
>
|
>
|
||||||
Sign In
|
Sign In
|
||||||
</Button>
|
</Button>
|
||||||
<Grid container>
|
|
||||||
<Grid item xs>
|
|
||||||
<Link href="#" variant="body2">
|
|
||||||
Forgot password?
|
|
||||||
</Link>
|
|
||||||
</Grid>
|
|
||||||
<Grid item>
|
|
||||||
<Link href="#" variant="body2">
|
|
||||||
{"Don't have an account? Sign Up"}
|
|
||||||
</Link>
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import React, { FC } from "react";
|
import React, { FC } from "react";
|
||||||
import { Header } from "../components/Header";
|
import Header from "../components/Header";
|
||||||
import { UserAvatar } from "./Avatars/UserAvatar";
|
import UserAvatar from "./Avatars/UserAvatar";
|
||||||
import {
|
import {
|
||||||
Grid,
|
Grid,
|
||||||
// makeStyles, Theme
|
// makeStyles, Theme
|
||||||
|
|
@ -19,7 +19,7 @@ interface IProps {
|
||||||
// },
|
// },
|
||||||
// }));
|
// }));
|
||||||
|
|
||||||
export const UserHeader: FC<IProps> = ({ fullName, presentation, picture }) => {
|
const UserHeader: FC<IProps> = ({ fullName, presentation, picture }) => {
|
||||||
// const classes = useStyles();
|
// const classes = useStyles();
|
||||||
return (
|
return (
|
||||||
// <div className={classes.root}>
|
// <div className={classes.root}>
|
||||||
|
|
@ -34,3 +34,5 @@ export const UserHeader: FC<IProps> = ({ fullName, presentation, picture }) => {
|
||||||
// </div>
|
// </div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default UserHeader;
|
||||||
|
|
|
||||||
7
client/src/constants/routes.ts
Normal file
7
client/src/constants/routes.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
export const HOME: string = "/";
|
||||||
|
export const PROJECTS: string = "/projects";
|
||||||
|
export const TICKETS: string = "/tickets";
|
||||||
|
export const USERS: string = "/users";
|
||||||
|
export const SIGN_IN: string = "/signin";
|
||||||
|
export const NOT_FOUND: string = "/404";
|
||||||
|
export const TEST: string = "/test";
|
||||||
|
|
@ -5,7 +5,7 @@ interface IProps {
|
||||||
error: string;
|
error: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ErrorController: FC<IProps> = ({ error }) => {
|
const ErrorController: FC<IProps> = ({ error }) => {
|
||||||
switch (error) {
|
switch (error) {
|
||||||
case "Bad Request":
|
case "Bad Request":
|
||||||
return <Redirect to="/400" />;
|
return <Redirect to="/400" />;
|
||||||
|
|
@ -20,3 +20,5 @@ export const ErrorController: FC<IProps> = ({ error }) => {
|
||||||
return <Redirect to="/404" />;
|
return <Redirect to="/404" />;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default ErrorController;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
import React, { FC } from "react";
|
import React, { FC } from "react";
|
||||||
import { HomePage } from "../pages/HomePage";
|
import HomePage from "../pages/HomePage";
|
||||||
|
|
||||||
export const HomeController: FC = () => {
|
const HomeController: FC = () => {
|
||||||
return <HomePage />;
|
return <HomePage />;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default HomeController;
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,15 @@
|
||||||
import React, { FC, useState, useEffect } from "react";
|
import React, { FC, useState, useEffect } from "react";
|
||||||
import { useParams } from "react-router-dom";
|
import { useParams } from "react-router-dom";
|
||||||
import { ErrorController } from "./ErrorController";
|
import ErrorController from "./ErrorController";
|
||||||
import { ProjectPage } from "../pages/ProjectPage";
|
import ProjectPage from "../pages/ProjectPage";
|
||||||
import ProjectVM from "../VM/ProjectVM";
|
import ProjectVM from "../VM/ProjectVM";
|
||||||
import { Project } from "../types/Project";
|
import Project from "../types/Project";
|
||||||
import { HttpResponse } from "../types/HttpResponse";
|
import User from "../types/User";
|
||||||
import { Preloader } from "../components/Preloader";
|
import Preloader from "../components/Preloader";
|
||||||
import { Constants } from "../utils/Constants";
|
import { ProjectService, UserService } from "../services";
|
||||||
import { get } from "../utils/http";
|
import { useAuth0 } from "../authentication/auth0";
|
||||||
import { User } from "../types/User";
|
|
||||||
|
|
||||||
export const ProjectController: FC = () => {
|
const ProjectController: FC = () => {
|
||||||
const [project, setProject] = useState<Project>({} as Project);
|
const [project, setProject] = useState<Project>({} as Project);
|
||||||
const [allUsers, setAllUsers] = useState<User[]>([]);
|
const [allUsers, setAllUsers] = useState<User[]>([]);
|
||||||
const [allProjects, setAllProjects] = useState<Project[]>([]);
|
const [allProjects, setAllProjects] = useState<Project[]>([]);
|
||||||
|
|
@ -18,61 +17,62 @@ export const ProjectController: FC = () => {
|
||||||
const [hasError, setHasError] = useState(false);
|
const [hasError, setHasError] = useState(false);
|
||||||
const [error, setError] = useState("");
|
const [error, setError] = useState("");
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
|
const { getTokenSilently } = useAuth0();
|
||||||
async function httpGetProjects(id: string): Promise<void> {
|
|
||||||
try {
|
|
||||||
const response: HttpResponse<Project> = await get<Project>(
|
|
||||||
`${Constants.projectsURI}/${id}`
|
|
||||||
);
|
|
||||||
if (response.parsedBody !== undefined) {
|
|
||||||
setProject(response.parsedBody);
|
|
||||||
setIsLoading(false);
|
|
||||||
}
|
|
||||||
} catch (ex) {
|
|
||||||
console.error(ex);
|
|
||||||
setHasError(true);
|
|
||||||
setError(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function httpGetAllUsers(): Promise<void> {
|
|
||||||
try {
|
|
||||||
const response: HttpResponse<User> = await get<User>(
|
|
||||||
`${Constants.usersURI}`
|
|
||||||
);
|
|
||||||
if (response.parsedBody !== undefined) {
|
|
||||||
setAllUsers((response.parsedBody as unknown) as User[]);
|
|
||||||
}
|
|
||||||
} catch (ex) {
|
|
||||||
setHasError(true);
|
|
||||||
setError(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function httpGetAllProjects(): Promise<void> {
|
|
||||||
try {
|
|
||||||
const response: HttpResponse<Project> = await get<Project>(
|
|
||||||
`${Constants.projectsURI}`
|
|
||||||
);
|
|
||||||
if (response.parsedBody !== undefined) {
|
|
||||||
setAllProjects((response.parsedBody as unknown) as Project[]);
|
|
||||||
}
|
|
||||||
} catch (ex) {
|
|
||||||
setHasError(true);
|
|
||||||
setError(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
const getProject = async (id: string): Promise<void> => {
|
||||||
|
const token = await getTokenSilently();
|
||||||
|
try {
|
||||||
|
const Projects = new ProjectService(token);
|
||||||
|
const project: Project = await Projects.get(id);
|
||||||
|
if (project !== undefined) {
|
||||||
|
setProject(project);
|
||||||
|
setIsLoading(false);
|
||||||
|
}
|
||||||
|
} catch (ex) {
|
||||||
|
setHasError(true);
|
||||||
|
setError(ex);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getAllUsers = async (): Promise<void> => {
|
||||||
|
const token = await getTokenSilently();
|
||||||
|
try {
|
||||||
|
const Users = new UserService(token);
|
||||||
|
const response: User[] = await Users.all();
|
||||||
|
if (response !== undefined) {
|
||||||
|
setAllUsers(response);
|
||||||
|
setIsLoading(false);
|
||||||
|
}
|
||||||
|
} catch (ex) {
|
||||||
|
setHasError(true);
|
||||||
|
setError(ex);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getAllProjects = async (): Promise<void> => {
|
||||||
|
const token = await getTokenSilently();
|
||||||
|
try {
|
||||||
|
const Projects = new ProjectService(token);
|
||||||
|
const response: Project[] = await Projects.all();
|
||||||
|
if (response !== undefined) {
|
||||||
|
setAllProjects(response);
|
||||||
|
}
|
||||||
|
} catch (ex) {
|
||||||
|
setHasError(true);
|
||||||
|
setError(ex);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (id !== undefined) {
|
if (id !== undefined) {
|
||||||
httpGetProjects(id);
|
getProject(id);
|
||||||
httpGetAllUsers();
|
getAllUsers();
|
||||||
httpGetAllProjects();
|
getAllProjects();
|
||||||
} else {
|
} else {
|
||||||
setHasError(true);
|
setHasError(true);
|
||||||
setError("Bad Request");
|
setError("Bad Request");
|
||||||
}
|
}
|
||||||
}, [id]);
|
}, [id, getTokenSilently]);
|
||||||
|
|
||||||
if (hasError) {
|
if (hasError) {
|
||||||
return <ErrorController error={error} />;
|
return <ErrorController error={error} />;
|
||||||
|
|
@ -81,3 +81,5 @@ export const ProjectController: FC = () => {
|
||||||
const viewModel = new ProjectVM(project, allUsers, allProjects);
|
const viewModel = new ProjectVM(project, allUsers, allProjects);
|
||||||
return isLoading ? <Preloader /> : <ProjectPage viewModel={viewModel} />;
|
return isLoading ? <Preloader /> : <ProjectPage viewModel={viewModel} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default ProjectController;
|
||||||
|
|
|
||||||
|
|
@ -1,45 +1,44 @@
|
||||||
import React, { FC, useState, useEffect } from "react";
|
import React, { FC, useState, useEffect } from "react";
|
||||||
import { useParams } from "react-router-dom";
|
import { useParams } from "react-router-dom";
|
||||||
import { TicketPage } from "../pages/TicketPage";
|
import ErrorController from "./ErrorController";
|
||||||
import { ErrorController } from "./ErrorController";
|
import TicketPage from "../pages/TicketPage";
|
||||||
import { HttpResponse } from "../types/HttpResponse";
|
import TicketVM from "../VM/TicketVM";
|
||||||
import { Preloader } from "../components/Preloader";
|
import Ticket from "../types/Ticket";
|
||||||
import { get } from "../utils/http";
|
import Preloader from "../components/Preloader";
|
||||||
import { Constants } from "../utils/Constants";
|
import { useAuth0 } from "../authentication/auth0";
|
||||||
import { Ticket } from "../types/Ticket";
|
import { TicketService } from "../services";
|
||||||
import { TicketVM } from "../VM/TicketVM";
|
|
||||||
|
|
||||||
export const TicketController: FC = () => {
|
const TicketController: FC = () => {
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
const [ticket, setTicket] = useState<Ticket>({} as Ticket);
|
const [ticket, setTicket] = useState<Ticket>({} as Ticket);
|
||||||
const [hasError, setHasError] = useState(false);
|
const [hasError, setHasError] = useState(false);
|
||||||
const [error, setError] = useState("");
|
const [error, setError] = useState("");
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
|
const { getTokenSilently } = useAuth0();
|
||||||
async function httpGetTicket(id: string): Promise<void> {
|
|
||||||
try {
|
|
||||||
const response: HttpResponse<Ticket> = await get<Ticket>(
|
|
||||||
`${Constants.ticketsURI}/${id}`
|
|
||||||
);
|
|
||||||
if (response.parsedBody !== undefined) {
|
|
||||||
setTicket(response.parsedBody);
|
|
||||||
setIsLoading(false);
|
|
||||||
}
|
|
||||||
} catch (ex) {
|
|
||||||
console.error(ex);
|
|
||||||
setHasError(true);
|
|
||||||
setError(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
const getTicket = async (id: string): Promise<void> => {
|
||||||
|
const token = await getTokenSilently();
|
||||||
|
try {
|
||||||
|
const Tickets = new TicketService(token);
|
||||||
|
const response: Ticket = await Tickets.get(id);
|
||||||
|
if (response !== undefined) {
|
||||||
|
setTicket(response);
|
||||||
|
setIsLoading(false);
|
||||||
|
}
|
||||||
|
} catch (ex) {
|
||||||
|
setHasError(true);
|
||||||
|
setError(ex);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (id !== undefined) {
|
if (id !== undefined) {
|
||||||
httpGetTicket(id);
|
getTicket(id);
|
||||||
} else {
|
} else {
|
||||||
setHasError(true);
|
setHasError(true);
|
||||||
setError("Bad Request");
|
setError("Bad Request");
|
||||||
}
|
}
|
||||||
}, [id]);
|
}, [id, getTokenSilently]);
|
||||||
|
|
||||||
if (hasError) {
|
if (hasError) {
|
||||||
return <ErrorController error={error} />;
|
return <ErrorController error={error} />;
|
||||||
|
|
@ -48,3 +47,5 @@ export const TicketController: FC = () => {
|
||||||
const viewModel = new TicketVM(ticket);
|
const viewModel = new TicketVM(ticket);
|
||||||
return isLoading ? <Preloader /> : <TicketPage viewModel={viewModel} />;
|
return isLoading ? <Preloader /> : <TicketPage viewModel={viewModel} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default TicketController;
|
||||||
|
|
|
||||||
|
|
@ -1,66 +1,75 @@
|
||||||
import React, { FC, useState, useEffect } from "react";
|
import React, { FC, useState, useEffect } from "react";
|
||||||
import { useParams } from "react-router-dom";
|
import { useParams } from "react-router-dom";
|
||||||
import { UserPage } from "../pages/UserPage";
|
import ErrorController from "./ErrorController";
|
||||||
|
import UserPage from "../pages/UserPage";
|
||||||
import { UserVM } from "../VM/UserVM";
|
import { UserVM } from "../VM/UserVM";
|
||||||
import { User } from "../types/User";
|
import User from "../types/User";
|
||||||
import { HttpResponse } from "../types/HttpResponse";
|
import Preloader from "../components/Preloader";
|
||||||
import { Preloader } from "../components/Preloader";
|
import { UserService } from "../services";
|
||||||
import { get } from "../utils/http";
|
import { useAuth0 } from "../authentication/auth0";
|
||||||
import { Constants } from "../utils/Constants";
|
import { getUID } from "../authentication/helpers";
|
||||||
import { ErrorController } from "./ErrorController";
|
|
||||||
|
|
||||||
export const UserController: FC = () => {
|
const UserController: FC = () => {
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
const [user, setUser] = useState<User>({} as User);
|
const [account, setAccount] = useState<User>({} as User);
|
||||||
const [hasError, setHasError] = useState(false);
|
const [hasError, setHasError] = useState(false);
|
||||||
const [error, setError] = useState("");
|
const [error, setError] = useState("");
|
||||||
const [allUsers, setAllUsers] = useState<User[]>([]);
|
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
|
const { getTokenSilently, user } = useAuth0();
|
||||||
async function httpGetUser(id: string): Promise<void> {
|
|
||||||
try {
|
|
||||||
const response: HttpResponse<User> = await get<User>(
|
|
||||||
`${Constants.usersURI}/${id}`
|
|
||||||
);
|
|
||||||
if (response.parsedBody !== undefined) {
|
|
||||||
setUser(response.parsedBody);
|
|
||||||
setIsLoading(false);
|
|
||||||
}
|
|
||||||
} catch (ex) {
|
|
||||||
console.error(ex);
|
|
||||||
setHasError(true);
|
|
||||||
setError(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function httpGetAllUsers(): Promise<void> {
|
|
||||||
try {
|
|
||||||
const response: HttpResponse<User> = await get<User>(
|
|
||||||
`${Constants.usersURI}`
|
|
||||||
);
|
|
||||||
if (response.parsedBody !== undefined) {
|
|
||||||
setAllUsers((response.parsedBody as unknown) as User[]);
|
|
||||||
}
|
|
||||||
} catch (ex) {
|
|
||||||
setHasError(true);
|
|
||||||
setError(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
const getUser = async (id: string): Promise<void> => {
|
||||||
|
const token = await getTokenSilently();
|
||||||
|
const Users = new UserService(token);
|
||||||
|
let response: User | undefined;
|
||||||
|
|
||||||
|
try {
|
||||||
|
response = await Users.get(id);
|
||||||
|
} catch (ex) {
|
||||||
|
if (ex === "Not Found") {
|
||||||
|
// create user
|
||||||
|
const { given_name, family_name, email, nickname, picture } = user;
|
||||||
|
const newUser: User = {
|
||||||
|
id: getUID(user),
|
||||||
|
firstName: given_name,
|
||||||
|
lastName: family_name,
|
||||||
|
fullName: `${given_name} ${family_name}`,
|
||||||
|
email,
|
||||||
|
presentation: nickname,
|
||||||
|
picture,
|
||||||
|
phone: "",
|
||||||
|
creationDate: Date.now().toLocaleString(),
|
||||||
|
activities: [],
|
||||||
|
projects: [],
|
||||||
|
tickets: [],
|
||||||
|
};
|
||||||
|
response = await Users.add(newUser);
|
||||||
|
} else {
|
||||||
|
setHasError(true);
|
||||||
|
setError(ex);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (response !== undefined) {
|
||||||
|
setAccount(response);
|
||||||
|
setIsLoading(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (id !== undefined) {
|
if (id !== undefined) {
|
||||||
httpGetUser(id);
|
getUser(id);
|
||||||
httpGetAllUsers();
|
|
||||||
} else {
|
} else {
|
||||||
setHasError(true);
|
setHasError(true);
|
||||||
setError("Bad Request");
|
setError("Bad Request");
|
||||||
}
|
}
|
||||||
}, [id]);
|
}, [id, getTokenSilently, user]);
|
||||||
|
|
||||||
if (hasError) {
|
if (hasError) {
|
||||||
return <ErrorController error={error} />;
|
return <ErrorController error={error} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
const viewModel = new UserVM(user, allUsers);
|
const viewModel = new UserVM(account);
|
||||||
return isLoading ? <Preloader /> : <UserPage viewModel={viewModel} />;
|
return isLoading ? <Preloader /> : <UserPage viewModel={viewModel} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default UserController;
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import { Auth0Provider } from "./authentication/auth0";
|
||||||
import config from "./authentication/config.json";
|
import config from "./authentication/config.json";
|
||||||
import history from "./utils/history";
|
import history from "./utils/history";
|
||||||
|
|
||||||
const onRedirectCallback = appState => {
|
const onRedirectCallback = (appState) => {
|
||||||
history.push(
|
history.push(
|
||||||
appState && appState.targetUrl
|
appState && appState.targetUrl
|
||||||
? appState.targetUrl
|
? appState.targetUrl
|
||||||
|
|
@ -18,6 +18,7 @@ ReactDOM.render(
|
||||||
<Auth0Provider
|
<Auth0Provider
|
||||||
domain={config.domain}
|
domain={config.domain}
|
||||||
client_id={config.clientId}
|
client_id={config.clientId}
|
||||||
|
audience={config.audience}
|
||||||
redirect_uri={window.location.origin}
|
redirect_uri={window.location.origin}
|
||||||
onRedirectCallback={onRedirectCallback}
|
onRedirectCallback={onRedirectCallback}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,7 @@
|
||||||
import React from "react";
|
import React, { FC } from "react";
|
||||||
// import { LogInForm } from "../components/LogInForm";
|
|
||||||
// import { ProfileSelector } from "../components/ProfileSelector";
|
|
||||||
import SignInSide from "../components/SignInSide";
|
|
||||||
|
|
||||||
export const HomePage: React.FC = () => {
|
const HomePage: FC = () => {
|
||||||
return (
|
return <div>HomePage</div>;
|
||||||
// <div className="section">
|
|
||||||
// <div className="container center">
|
|
||||||
// <h1 className="center">Ticket Manager</h1>
|
|
||||||
// <div className="row">
|
|
||||||
// <div className="col s6">
|
|
||||||
// <ProfileSelector />
|
|
||||||
// </div>
|
|
||||||
// <div className="col s6">
|
|
||||||
// <LogInForm />
|
|
||||||
// </div>
|
|
||||||
// </div>
|
|
||||||
// </div>
|
|
||||||
// </div>
|
|
||||||
<SignInSide />
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default HomePage;
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,8 @@
|
||||||
import React, { FC } from "react";
|
import React, { FC } from "react";
|
||||||
import PageLayout from "../layouts/PageLayout";
|
import PageLayout from "../layouts/PageLayout";
|
||||||
import { Header } from "../components/Header";
|
import Header from "../components/Header";
|
||||||
|
|
||||||
interface IProps {}
|
const NotFoundPage: FC = () => {
|
||||||
export const NotFoundPage: FC<IProps> = () => {
|
|
||||||
return (
|
return (
|
||||||
<PageLayout
|
<PageLayout
|
||||||
header={<Header title="Error page" description="Something went wrong" />}
|
header={<Header title="Error page" description="Something went wrong" />}
|
||||||
|
|
@ -11,3 +10,5 @@ export const NotFoundPage: FC<IProps> = () => {
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default NotFoundPage;
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
import React, { FC, useState } from "react";
|
import React, { FC, useState } from "react";
|
||||||
import { Grid, makeStyles, Theme } from "@material-ui/core";
|
import { Grid, makeStyles, Theme } from "@material-ui/core";
|
||||||
import { Header } from "../components/Header";
|
import Header from "../components/Header";
|
||||||
import { AvatarList } from "../components/Avatars/AvatarList";
|
import AvatarList from "../components/Avatars/AvatarList";
|
||||||
import { ProgressBar } from "../components/Progress/ProgressBar";
|
import ProgressBar from "../components/Progress/ProgressBar";
|
||||||
import { FloatingButton } from "../components/Buttons/FloatingButton";
|
import FloatingButton from "../components/Buttons/FloatingButton";
|
||||||
import { UsersModal } from "../components/Modals/UsersModal";
|
import UsersModal from "../components/Modals/UsersModal";
|
||||||
import { ProjectTabPanel } from "../components/Panels/ProjectTabPanel";
|
import ProjectTabPanel from "../components/Panels/ProjectTabPanel";
|
||||||
|
import ProgressInfo from "../components/Progress/ProgressInfo";
|
||||||
import ProjectVM from "../VM/ProjectVM";
|
import ProjectVM from "../VM/ProjectVM";
|
||||||
import PageLayout from "../layouts/PageLayout";
|
import PageLayout from "../layouts/PageLayout";
|
||||||
import { ProgressInfo } from "../components/Progress/ProgressInfo";
|
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
viewModel: ProjectVM;
|
viewModel: ProjectVM;
|
||||||
|
|
@ -22,7 +22,7 @@ const useStyles = makeStyles((theme: Theme) => ({
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const ProjectPage: FC<IProps> = ({ viewModel }) => {
|
const ProjectPage: FC<IProps> = ({ viewModel }) => {
|
||||||
const {
|
const {
|
||||||
// id,
|
// id,
|
||||||
title,
|
title,
|
||||||
|
|
@ -97,3 +97,5 @@ export const ProjectPage: FC<IProps> = ({ viewModel }) => {
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default ProjectPage;
|
||||||
|
|
|
||||||
20
client/src/pages/SigninPage.tsx
Normal file
20
client/src/pages/SigninPage.tsx
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
import React, { FC } from "react";
|
||||||
|
import { Redirect } from "react-router-dom";
|
||||||
|
import SignInSide from "../components/SignInSide";
|
||||||
|
import { useAuth0 } from "../authentication/auth0";
|
||||||
|
import { getUID } from "../authentication/helpers";
|
||||||
|
import * as ROUTES from "../constants/routes";
|
||||||
|
|
||||||
|
const SigninPage: FC = () => {
|
||||||
|
const { isAuthenticated, user } = useAuth0();
|
||||||
|
|
||||||
|
if (isAuthenticated) {
|
||||||
|
// retrieve userId
|
||||||
|
const uid = getUID(user);
|
||||||
|
return <Redirect to={`${ROUTES.USERS}/${uid}`} />;
|
||||||
|
} else {
|
||||||
|
return <SignInSide />;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SigninPage;
|
||||||
|
|
@ -2,12 +2,12 @@ import React, { FC } from "react";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { makeStyles, Theme, Grid, Typography } from "@material-ui/core";
|
import { makeStyles, Theme, Grid, Typography } from "@material-ui/core";
|
||||||
import { Timer } from "@material-ui/icons";
|
import { Timer } from "@material-ui/icons";
|
||||||
|
import TicketVM from "../VM/TicketVM";
|
||||||
import PageLayout from "../layouts/PageLayout";
|
import PageLayout from "../layouts/PageLayout";
|
||||||
import { TicketVM } from "../VM/TicketVM";
|
import Header from "../components/Header";
|
||||||
import { Header } from "../components/Header";
|
import AvatarList from "../components/Avatars/AvatarList";
|
||||||
import { AvatarList } from "../components/Avatars/AvatarList";
|
|
||||||
import TicketChipsArray from "../components/Cards/TicketChipsArray";
|
import TicketChipsArray from "../components/Cards/TicketChipsArray";
|
||||||
import { getRemainingdays } from "../utils/methods";
|
import getRemainingdays from "../utils/methods";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
viewModel: TicketVM;
|
viewModel: TicketVM;
|
||||||
|
|
@ -16,7 +16,6 @@ interface IProps {
|
||||||
const useStyles = makeStyles((theme: Theme) => ({
|
const useStyles = makeStyles((theme: Theme) => ({
|
||||||
root: {
|
root: {
|
||||||
margin: theme.spacing(1),
|
margin: theme.spacing(1),
|
||||||
// flexGrow: 1,
|
|
||||||
},
|
},
|
||||||
table: {
|
table: {
|
||||||
margin: "auto",
|
margin: "auto",
|
||||||
|
|
@ -28,7 +27,7 @@ const useStyles = makeStyles((theme: Theme) => ({
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const TicketPage: FC<IProps> = ({ viewModel }) => {
|
const TicketPage: FC<IProps> = ({ viewModel }) => {
|
||||||
const {
|
const {
|
||||||
title,
|
title,
|
||||||
description,
|
description,
|
||||||
|
|
@ -133,3 +132,5 @@ export const TicketPage: FC<IProps> = ({ viewModel }) => {
|
||||||
// </TableContainer>
|
// </TableContainer>
|
||||||
// );
|
// );
|
||||||
// };
|
// };
|
||||||
|
|
||||||
|
export default TicketPage;
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,15 @@
|
||||||
import React, { FC } from "react";
|
import React, { FC } from "react";
|
||||||
import { UserVM } from "../VM/UserVM";
|
import { UserVM } from "../VM/UserVM";
|
||||||
import { UserHeader } from "../components/UserHeader";
|
import UserHeader from "../components/UserHeader";
|
||||||
import { UserTabPanel } from "../components/Panels/UserTabPanel";
|
import UserTabPanel from "../components/Panels/UserTabPanel";
|
||||||
import PageLayout from "../layouts/PageLayout";
|
import PageLayout from "../layouts/PageLayout";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
viewModel: UserVM;
|
viewModel: UserVM;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const UserPage: FC<IProps> = ({ viewModel }) => {
|
const UserPage: FC<IProps> = ({ viewModel }) => {
|
||||||
const {
|
const { fullName, presentation, picture, projects, tickets } = viewModel;
|
||||||
fullName,
|
|
||||||
presentation,
|
|
||||||
picture,
|
|
||||||
projects,
|
|
||||||
tickets,
|
|
||||||
allUsers,
|
|
||||||
} = viewModel;
|
|
||||||
const tabNames: string[] = ["Projects", "Tickets"];
|
const tabNames: string[] = ["Projects", "Tickets"];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -33,9 +26,10 @@ export const UserPage: FC<IProps> = ({ viewModel }) => {
|
||||||
tabNames={tabNames}
|
tabNames={tabNames}
|
||||||
projects={projects}
|
projects={projects}
|
||||||
tickets={tickets}
|
tickets={tickets}
|
||||||
allUsers={allUsers}
|
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default UserPage;
|
||||||
|
|
|
||||||
33
client/src/routes/AppRouter.tsx
Normal file
33
client/src/routes/AppRouter.tsx
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
import React from "react";
|
||||||
|
import { Route, Switch } from "react-router-dom";
|
||||||
|
import PrivateRoute from "./PrivateRoute";
|
||||||
|
import HomeController from "../controllers/HomeController";
|
||||||
|
import ProjectController from "../controllers/ProjectController";
|
||||||
|
import UserController from "../controllers/UserController";
|
||||||
|
import TicketController from "../controllers/TicketController";
|
||||||
|
import NotFoundPage from "../pages/NotFoundPage";
|
||||||
|
import TestPage from "../pages/TestPage";
|
||||||
|
import SigninPage from "../pages/SigninPage";
|
||||||
|
import * as ROUTES from "../constants/routes";
|
||||||
|
|
||||||
|
const AppRouter = () => {
|
||||||
|
return (
|
||||||
|
<Switch>
|
||||||
|
<PrivateRoute path={ROUTES.TEST} component={TestPage} />
|
||||||
|
<Route exact path={ROUTES.HOME} component={HomeController} />
|
||||||
|
<Route path={ROUTES.SIGN_IN} component={SigninPage} />
|
||||||
|
<PrivateRoute
|
||||||
|
path={`${ROUTES.PROJECTS}/:id`}
|
||||||
|
component={ProjectController}
|
||||||
|
/>
|
||||||
|
<PrivateRoute
|
||||||
|
path={`${ROUTES.TICKETS}/:id`}
|
||||||
|
component={TicketController}
|
||||||
|
/>
|
||||||
|
<PrivateRoute path={`${ROUTES.USERS}/:id`} component={UserController} />
|
||||||
|
<Route path={ROUTES.NOT_FOUND} component={NotFoundPage} />
|
||||||
|
</Switch>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AppRouter;
|
||||||
|
|
@ -2,7 +2,7 @@ import React, { useEffect } from "react";
|
||||||
import { Route } from "react-router-dom";
|
import { Route } from "react-router-dom";
|
||||||
import { useAuth0 } from "../authentication/auth0";
|
import { useAuth0 } from "../authentication/auth0";
|
||||||
|
|
||||||
export const PrivateRoute = ({ component: Component, path, ...rest }) => {
|
const PrivateRoute = ({ component: Component, path, ...rest }) => {
|
||||||
const { loading, isAuthenticated, loginWithRedirect } = useAuth0();
|
const { loading, isAuthenticated, loginWithRedirect } = useAuth0();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -11,14 +11,16 @@ export const PrivateRoute = ({ component: Component, path, ...rest }) => {
|
||||||
}
|
}
|
||||||
const fn = async () => {
|
const fn = async () => {
|
||||||
await loginWithRedirect({
|
await loginWithRedirect({
|
||||||
appState: { targetUrl: window.location.pathname }
|
appState: { targetUrl: window.location.pathname },
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
fn();
|
fn();
|
||||||
}, [loading, isAuthenticated, loginWithRedirect, path]);
|
}, [loading, isAuthenticated, loginWithRedirect, path]);
|
||||||
|
|
||||||
const render = props =>
|
const render = (props) =>
|
||||||
isAuthenticated === true ? <Component {...props} /> : null;
|
isAuthenticated === true ? <Component {...props} /> : null;
|
||||||
|
|
||||||
return <Route path={path} render={render} {...rest} />;
|
return <Route path={path} render={render} {...rest} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default PrivateRoute;
|
||||||
72
client/src/services/http.ts
Normal file
72
client/src/services/http.ts
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
import HttpResponse from "../types/HttpResponse";
|
||||||
|
|
||||||
|
export default class HttpHandler<T> {
|
||||||
|
private newHeaders = async (token: string) => {
|
||||||
|
// const { getTokenSilently } = useAuth0();
|
||||||
|
// const token = await getTokenSilently();
|
||||||
|
|
||||||
|
return new Headers({
|
||||||
|
Accept: "application/json",
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
private execute = async (request: RequestInfo): Promise<HttpResponse<T>> => {
|
||||||
|
const response: HttpResponse<T> = await fetch(request);
|
||||||
|
try {
|
||||||
|
response.parsedBody = await response.json();
|
||||||
|
} catch (ex) {}
|
||||||
|
if (!response.ok) {
|
||||||
|
throw response.statusText;
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
};
|
||||||
|
|
||||||
|
get = async (path: string, token: string): Promise<HttpResponse<T>> => {
|
||||||
|
const args: RequestInit = {
|
||||||
|
method: "get",
|
||||||
|
headers: await this.newHeaders(token),
|
||||||
|
};
|
||||||
|
return await this.execute(new Request(path, args));
|
||||||
|
};
|
||||||
|
|
||||||
|
post = async (
|
||||||
|
path: string,
|
||||||
|
body: any,
|
||||||
|
token: string
|
||||||
|
): Promise<HttpResponse<T>> => {
|
||||||
|
const args: RequestInit = {
|
||||||
|
method: "post",
|
||||||
|
headers: await this.newHeaders(token),
|
||||||
|
body: JSON.stringify(body),
|
||||||
|
};
|
||||||
|
return await this.execute(new Request(path, args));
|
||||||
|
};
|
||||||
|
|
||||||
|
put = async (
|
||||||
|
path: string,
|
||||||
|
body: any,
|
||||||
|
token: string
|
||||||
|
): Promise<HttpResponse<T>> => {
|
||||||
|
const args: RequestInit = {
|
||||||
|
method: "put",
|
||||||
|
headers: await this.newHeaders(token),
|
||||||
|
body: JSON.stringify(body),
|
||||||
|
};
|
||||||
|
return await this.execute(new Request(path, args));
|
||||||
|
};
|
||||||
|
|
||||||
|
patch = async (
|
||||||
|
path: string,
|
||||||
|
body: any,
|
||||||
|
token: string
|
||||||
|
): Promise<HttpResponse<T>> => {
|
||||||
|
const args: RequestInit = {
|
||||||
|
method: "patch",
|
||||||
|
headers: await this.newHeaders(token),
|
||||||
|
body: JSON.stringify(body),
|
||||||
|
};
|
||||||
|
return await this.execute(new Request(path, args));
|
||||||
|
};
|
||||||
|
}
|
||||||
13
client/src/services/index.ts
Normal file
13
client/src/services/index.ts
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
import ProjectService from "./project";
|
||||||
|
import TicketService from "./ticket";
|
||||||
|
import UserService from "./user";
|
||||||
|
|
||||||
|
export default interface IService<T> {
|
||||||
|
all(): Promise<T[]>;
|
||||||
|
get(id: string): Promise<T>;
|
||||||
|
add(item: any): Promise<T>;
|
||||||
|
update(id: string, item: T): Promise<void>;
|
||||||
|
delete(id: string): Promise<void>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export { ProjectService, TicketService, UserService };
|
||||||
44
client/src/services/project.ts
Normal file
44
client/src/services/project.ts
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
import IService from ".";
|
||||||
|
import Project from "../types/Project";
|
||||||
|
import HttpHandler from "./http";
|
||||||
|
|
||||||
|
interface NewProject {
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
endingDate: string;
|
||||||
|
managerId: string;
|
||||||
|
}
|
||||||
|
export default class ProjectService implements IService<Project> {
|
||||||
|
constructor(private key: string) {}
|
||||||
|
|
||||||
|
private http = new HttpHandler<Project>();
|
||||||
|
private path: string = "/api/v1/projects";
|
||||||
|
|
||||||
|
all = async (): Promise<Project[]> => {
|
||||||
|
const response = await this.http.get(this.path, this.key);
|
||||||
|
return (response.parsedBody as unknown) as Project[];
|
||||||
|
};
|
||||||
|
|
||||||
|
get = async (id: string): Promise<Project> => {
|
||||||
|
const response = await this.http.get(`${this.path}/${id}`, this.key);
|
||||||
|
const body = response.parsedBody;
|
||||||
|
return body ?? ({} as Project);
|
||||||
|
};
|
||||||
|
|
||||||
|
add = async (item: NewProject): Promise<Project> => {
|
||||||
|
const response = await this.http.post(this.path, item, this.key);
|
||||||
|
const body = response.parsedBody;
|
||||||
|
return body ?? ({} as Project);
|
||||||
|
};
|
||||||
|
|
||||||
|
update(id: string, item: Project): Promise<void> {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
delete(id: string): Promise<void> {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
|
||||||
|
setMembers = async (id: string, members: string[]): Promise<void> => {
|
||||||
|
await this.http.patch(`${this.path}/${id}/members`, members, this.key);
|
||||||
|
};
|
||||||
|
}
|
||||||
50
client/src/services/ticket.ts
Normal file
50
client/src/services/ticket.ts
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
import IService from ".";
|
||||||
|
import Ticket from "../types/Ticket";
|
||||||
|
import HttpHandler from "./http";
|
||||||
|
|
||||||
|
interface NewTicket {
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
endingDate: string;
|
||||||
|
creatorId: string;
|
||||||
|
projectId: number;
|
||||||
|
impact: number;
|
||||||
|
difficulty: number;
|
||||||
|
category: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class TicketService implements IService<Ticket> {
|
||||||
|
constructor(private key: string) {}
|
||||||
|
|
||||||
|
private http = new HttpHandler<Ticket>();
|
||||||
|
private path: string = "/api/v1/tickets";
|
||||||
|
|
||||||
|
all = async (): Promise<Ticket[]> => {
|
||||||
|
const response = await this.http.get(this.path, this.key);
|
||||||
|
return (response.parsedBody as unknown) as Ticket[];
|
||||||
|
};
|
||||||
|
|
||||||
|
get = async (id: string): Promise<Ticket> => {
|
||||||
|
const response = await this.http.get(`${this.path}/${id}`, this.key);
|
||||||
|
const body = response.parsedBody;
|
||||||
|
return body ?? ({} as Ticket);
|
||||||
|
};
|
||||||
|
|
||||||
|
add = async (item: NewTicket): Promise<Ticket> => {
|
||||||
|
const response = await this.http.post(this.path, item, this.key);
|
||||||
|
const body = response.parsedBody;
|
||||||
|
return body ?? ({} as Ticket);
|
||||||
|
};
|
||||||
|
|
||||||
|
update(id: string, item: Ticket): Promise<void> {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(id: string): Promise<void> {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
}
|
||||||
|
|
||||||
|
close = async (id: string): Promise<void> => {
|
||||||
|
await this.http.put(`${this.path}/${id}/closed`, {}, this.key);
|
||||||
|
};
|
||||||
|
}
|
||||||
35
client/src/services/user.ts
Normal file
35
client/src/services/user.ts
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
import IService from ".";
|
||||||
|
import User from "../types/User";
|
||||||
|
import HttpHandler from "./http";
|
||||||
|
|
||||||
|
export default class UserService implements IService<User> {
|
||||||
|
constructor(private key: string) {}
|
||||||
|
|
||||||
|
private http = new HttpHandler<User>();
|
||||||
|
private path: string = "/api/v1/users";
|
||||||
|
|
||||||
|
all = async (): Promise<User[]> => {
|
||||||
|
const response = await this.http.get(this.path, this.key);
|
||||||
|
return (response.parsedBody as unknown) as User[];
|
||||||
|
};
|
||||||
|
|
||||||
|
get = async (id: string): Promise<User> => {
|
||||||
|
const response = await this.http.get(`${this.path}/${id}`, this.key);
|
||||||
|
const body = response.parsedBody;
|
||||||
|
return body ?? ({} as User);
|
||||||
|
};
|
||||||
|
|
||||||
|
add = async (item: User): Promise<User> => {
|
||||||
|
const response = await this.http.post(this.path, item, this.key);
|
||||||
|
const body = response.parsedBody;
|
||||||
|
return body ?? ({} as User);
|
||||||
|
};
|
||||||
|
|
||||||
|
update = async (id: string, item: User): Promise<void> => {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
};
|
||||||
|
|
||||||
|
delete = async (id: string): Promise<void> => {
|
||||||
|
throw new Error("Method not implemented.");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { User } from "./User";
|
import User from "./User";
|
||||||
import { Ticket } from "./Ticket";
|
import Ticket from "./Ticket";
|
||||||
|
|
||||||
export interface Activity {
|
export default interface Activity {
|
||||||
id: number;
|
id: number;
|
||||||
description: string;
|
description: string;
|
||||||
date: Date;
|
date: Date;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { User } from "./User";
|
import User from "./User";
|
||||||
|
|
||||||
export interface AppFile {
|
export default interface AppFile {
|
||||||
id: number;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
description: string;
|
description: string;
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
export interface HttpResponse<T> extends Response {
|
export default interface HttpResponse<T> extends Response {
|
||||||
parsedBody?: T;
|
parsedBody?: T;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
export interface Note {
|
export default interface Note {
|
||||||
Id: number;
|
Id: number;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import { Ticket } from "./Ticket";
|
import AppFile from "./AppFile";
|
||||||
import { User } from "./User";
|
import Activity from "./Activity";
|
||||||
import { AppFile } from "./AppFile";
|
import Ticket from "./Ticket";
|
||||||
import { Activity } from "./Activity";
|
import User from "./User";
|
||||||
|
|
||||||
export interface Project {
|
export default interface Project {
|
||||||
id: number;
|
id: number;
|
||||||
title: string;
|
title: string;
|
||||||
description: string;
|
description: string;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { Project } from "./Project";
|
import Project from "./Project";
|
||||||
import { User } from "./User";
|
import User from "./User";
|
||||||
|
|
||||||
export interface Ticket {
|
export default interface Ticket {
|
||||||
id: number;
|
id: number;
|
||||||
title: string;
|
title: string;
|
||||||
description: string;
|
description: string;
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import { Activity } from "./Activity";
|
import Activity from "./Activity";
|
||||||
import { Project } from "./Project";
|
import Project from "./Project";
|
||||||
import { Ticket } from "./Ticket";
|
import Ticket from "./Ticket";
|
||||||
|
|
||||||
export interface User {
|
export default interface User {
|
||||||
id: string;
|
id: string;
|
||||||
firstName: string;
|
firstName: string;
|
||||||
lastName: string;
|
lastName: string;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
export class Constants {
|
export default class Constants {
|
||||||
static projectsURI: string = "/api/v1/projects";
|
static projectsURI: string = "/api/v1/projects";
|
||||||
static ticketsURI: string = "/api/v1/tickets";
|
static ticketsURI: string = "/api/v1/tickets";
|
||||||
static usersURI: string = "/api/v1/users";
|
static usersURI: string = "/api/v1/users";
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,4 @@
|
||||||
import { createBrowserHistory } from "history";
|
import * as createHistory from "history";
|
||||||
export default createBrowserHistory;
|
const history = createHistory.createBrowserHistory();
|
||||||
|
|
||||||
|
export default history;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { HttpResponse } from "../types/HttpResponse";
|
import HttpResponse from "../types/HttpResponse";
|
||||||
|
|
||||||
export async function http<T>(request: RequestInfo): Promise<HttpResponse<T>> {
|
export async function http<T>(request: RequestInfo): Promise<HttpResponse<T>> {
|
||||||
const response: HttpResponse<T> = await fetch(request);
|
const response: HttpResponse<T> = await fetch(request);
|
||||||
|
|
@ -24,7 +24,7 @@ export async function post<T>(
|
||||||
args: RequestInit = {
|
args: RequestInit = {
|
||||||
method: "post",
|
method: "post",
|
||||||
headers: headers,
|
headers: headers,
|
||||||
body: JSON.stringify(body)
|
body: JSON.stringify(body),
|
||||||
}
|
}
|
||||||
): Promise<HttpResponse<T>> {
|
): Promise<HttpResponse<T>> {
|
||||||
return await http<T>(new Request(path, args));
|
return await http<T>(new Request(path, args));
|
||||||
|
|
@ -36,7 +36,7 @@ export async function put<T>(
|
||||||
args: RequestInit = {
|
args: RequestInit = {
|
||||||
method: "put",
|
method: "put",
|
||||||
headers: headers,
|
headers: headers,
|
||||||
body: JSON.stringify(body)
|
body: JSON.stringify(body),
|
||||||
}
|
}
|
||||||
): Promise<HttpResponse<T>> {
|
): Promise<HttpResponse<T>> {
|
||||||
return await http<T>(new Request(path, args));
|
return await http<T>(new Request(path, args));
|
||||||
|
|
@ -48,7 +48,7 @@ export async function patch<T>(
|
||||||
args: RequestInit = {
|
args: RequestInit = {
|
||||||
method: "patch",
|
method: "patch",
|
||||||
headers: headers,
|
headers: headers,
|
||||||
body: JSON.stringify(body)
|
body: JSON.stringify(body),
|
||||||
}
|
}
|
||||||
): Promise<HttpResponse<T>> {
|
): Promise<HttpResponse<T>> {
|
||||||
return await http<T>(new Request(path, args));
|
return await http<T>(new Request(path, args));
|
||||||
|
|
@ -58,5 +58,5 @@ const headers: Headers = new Headers({
|
||||||
Accept: "application/json",
|
Accept: "application/json",
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
Authorization:
|
Authorization:
|
||||||
"Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Ik1UWkNSRFEzUkRnd1FUQXlNRFExTmtOQ09UQXlSamhGTURaRU1Ea3pNRGxHUkRrelFqZENSZyJ9.eyJpc3MiOiJodHRwczovL2Rldi1meWpydm9oeC5hdXRoMC5jb20vIiwic3ViIjoiR3dlZTlGUnN3ejNWNE5vZFVRTjJIcjJyQjJTMDI1UmZAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbG9jYWxob3N0OjUwMDEvYXBpL1YxLyIsImlhdCI6MTU4NDE5ODQ4MCwiZXhwIjoxNTg0Mjg0ODgwLCJhenAiOiJHd2VlOUZSc3d6M1Y0Tm9kVVFOMkhyMnJCMlMwMjVSZiIsImd0eSI6ImNsaWVudC1jcmVkZW50aWFscyJ9.I1D49ILGBLhnq9biIA0y6Ra93zTKRDJI_rfGvU05MtT1zkI1ZliX9P-7LyKeWBv8tPonB6gT12lJiai_GHBET8kKbXNqwfVvDJ3eqYK-TtTqfL65RfWL9tQfQybHbfuF9M0oiXMqWMqmsc5Umpp4a3bLTQgwkUEKxcdMm84L7zoaqMycns4mFojWpQJKfPa64oZFDIXYy6hPDXcX50Djuk1m-aqMhtpmqkZvPfwEjvtEtGGCTOJHV7uugn3r8Wk4HX02ShrV676GICE1Yw7eHufAbY7yvHz3ImZ1cfEVrRbbijPA2vogXd5RmqNyindDDlT1Y_C80U0DyvhS7P7apQ"
|
"Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Ik1UWkNSRFEzUkRnd1FUQXlNRFExTmtOQ09UQXlSamhGTURaRU1Ea3pNRGxHUkRrelFqZENSZyJ9.eyJpc3MiOiJodHRwczovL2Rldi1meWpydm9oeC5hdXRoMC5jb20vIiwic3ViIjoiR3dlZTlGUnN3ejNWNE5vZFVRTjJIcjJyQjJTMDI1UmZAY2xpZW50cyIsImF1ZCI6Imh0dHBzOi8vbG9jYWxob3N0OjUwMDEvYXBpL1YxLyIsImlhdCI6MTU4NDE5ODQ4MCwiZXhwIjoxNTg0Mjg0ODgwLCJhenAiOiJHd2VlOUZSc3d6M1Y0Tm9kVVFOMkhyMnJCMlMwMjVSZiIsImd0eSI6ImNsaWVudC1jcmVkZW50aWFscyJ9.I1D49ILGBLhnq9biIA0y6Ra93zTKRDJI_rfGvU05MtT1zkI1ZliX9P-7LyKeWBv8tPonB6gT12lJiai_GHBET8kKbXNqwfVvDJ3eqYK-TtTqfL65RfWL9tQfQybHbfuF9M0oiXMqWMqmsc5Umpp4a3bLTQgwkUEKxcdMm84L7zoaqMycns4mFojWpQJKfPa64oZFDIXYy6hPDXcX50Djuk1m-aqMhtpmqkZvPfwEjvtEtGGCTOJHV7uugn3r8Wk4HX02ShrV676GICE1Yw7eHufAbY7yvHz3ImZ1cfEVrRbbijPA2vogXd5RmqNyindDDlT1Y_C80U0DyvhS7P7apQ",
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,12 @@
|
||||||
export const getRemainingdays: (endDate: string) => number = (
|
const getRemainingdays: (endDate: string) => number = (endDate: string) => {
|
||||||
endDate: string
|
|
||||||
) => {
|
|
||||||
let endingDate: Date = new Date(endDate);
|
let endingDate: Date = new Date(endDate);
|
||||||
let today: Date = new Date();
|
let today: Date = new Date();
|
||||||
return Math.abs(endingDate.getDate() - today.getDate());
|
return Math.abs(endingDate.getDate() - today.getDate());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default getRemainingdays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get today date
|
||||||
|
*/
|
||||||
|
export const today = (): string => new Date().toISOString().split("T")[0];
|
||||||
|
|
|
||||||
|
|
@ -1,37 +0,0 @@
|
||||||
import React from "react";
|
|
||||||
import { Route, Switch } from "react-router-dom";
|
|
||||||
import { HomeController } from "../controllers/HomeController";
|
|
||||||
import { ProjectController } from "../controllers/ProjectController";
|
|
||||||
import { UserController } from "../controllers/UserController";
|
|
||||||
import { TicketController } from "../controllers/TicketController";
|
|
||||||
import { NotFoundPage } from "../pages/NotFoundPage";
|
|
||||||
|
|
||||||
export const AppRouter = () => {
|
|
||||||
return (
|
|
||||||
<Switch>
|
|
||||||
{/* <PrivateRoute exact path="/test">
|
|
||||||
<TestPage />
|
|
||||||
</PrivateRoute> */}
|
|
||||||
|
|
||||||
<Route exact path="/">
|
|
||||||
<HomeController />
|
|
||||||
</Route>
|
|
||||||
|
|
||||||
<Route path="/users/:id">
|
|
||||||
<UserController />
|
|
||||||
</Route>
|
|
||||||
|
|
||||||
<Route path="/projects/:id">
|
|
||||||
<ProjectController />
|
|
||||||
</Route>
|
|
||||||
|
|
||||||
<Route path="/tickets/:id">
|
|
||||||
<TicketController />
|
|
||||||
</Route>
|
|
||||||
|
|
||||||
<Route path="/404">
|
|
||||||
<NotFoundPage />
|
|
||||||
</Route>
|
|
||||||
</Switch>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "es5",
|
"target": "es6",
|
||||||
"lib": ["dom", "dom.iterable", "esnext"],
|
"lib": ["dom", "dom.iterable", "esnext"],
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
|
|
@ -13,7 +13,14 @@
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
"jsx": "react"
|
"jsx": "react",
|
||||||
|
"sourceMap": true,
|
||||||
|
"declaration": false,
|
||||||
|
"emitDecoratorMetadata": true,
|
||||||
|
"downlevelIteration": true,
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"importHelpers": true,
|
||||||
|
"typeRoots": ["node_modules/@types"]
|
||||||
},
|
},
|
||||||
"include": ["src"]
|
"include": ["src"]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue