35 Commits

Author SHA1 Message Date
d705e02dc2 Fixes. 2023-05-21 21:56:19 +04:00
2d238b59ea Error handlers. 2023-05-21 20:10:04 +04:00
cca786bc4b Merge branch 'CourseworkRestAPI' into CourseworkEmployeeApp 2023-05-21 02:45:10 +04:00
00a90506c8 Handlers of possible errors. 2023-05-21 02:44:25 +04:00
e36877d0db Storage fixes. 2023-05-20 06:20:52 +04:00
f82fc6157c Merge branch 'CourseworkRestAPI' into CourseworkEmployeeApp 2023-05-20 05:58:42 +04:00
474eaefff6 Bunch of fixes. 2023-05-20 05:58:06 +04:00
3a2a5683f3 Merge branch 'CourseworkRestAPI' into CourseworkEmployeeApp 2023-05-20 02:23:26 +04:00
8ef56e41f0 Views for excel/word. 2023-05-20 02:22:02 +04:00
6a587d523c Merging RestAPI to EmployeeApp 2023-05-19 19:24:27 +04:00
474e15675b Merge branch 'CourseworkRestAPI' into CourseworkEmployeeApp 2023-05-19 18:58:49 +04:00
5802a5a4dd File saving methods. 2023-05-19 18:57:49 +04:00
54dadbeb7e Merge branch 'CourseworkRestAPI' into CourseworkEmployeeApp 2023-05-19 17:00:46 +04:00
30663c7429 Merge branch 'CourseworkRestAPI' into CourseworkEmployeeApp 2023-05-19 16:56:43 +04:00
1a10fbed1d Merge branch 'CourseworkRestAPI' into CourseworkEmployeeApp 2023-05-19 16:51:14 +04:00
55ce9512ea Merging with RestAPI. 2023-05-19 16:05:55 +04:00
df16e3dba4 Report views. 2023-05-19 16:01:34 +04:00
f777a0ee3c Merging restAPI to EmpoyeeApp 2023-05-19 13:40:41 +04:00
ad23e94dea Merging RestAPI to EmployeeApp 2023-05-19 02:43:59 +04:00
96e135f0a1 Merge branch 'CourseworkRestAPI' into CourseworkEmployeeApp 2023-05-19 02:32:33 +04:00
28c48c45c5 Merging rest api to employee app 2023-05-18 03:00:42 +04:00
bd52da4a56 Merge branch 'CourseworkRestAPI' into CourseworkEmployeeApp 2023-05-17 22:59:19 +04:00
b4b10c4eb6 removing unnecessary rows. 2023-05-17 22:28:52 +04:00
156f8dc820 IDK... 2023-05-17 22:27:48 +04:00
89eaf4c5b4 Merging RestAPI to EmployeeApp 2023-05-17 18:39:36 +04:00
27fc34b712 Views for PC 2023-05-17 17:54:05 +04:00
82be9eab7d ProductViews are finally done + fixes in product logic/storage/model. 2023-05-15 19:14:40 +04:00
eeda90cb78 A damn bunch of fixes + a couple of views for product. 2023-05-14 22:11:06 +04:00
3385f124d0 Product views + api/logic/storage fixes. 2023-05-14 02:14:53 +04:00
2fec7dfdf0 Views changes. 2023-05-13 22:46:59 +04:00
c5603b1ceb RestAPI merging + views changes. 2023-05-13 22:46:33 +04:00
a2d01ef8de Merge branch 'CourseworkRestAPI' into CourseworkEmployeeApp 2023-05-13 22:17:34 +04:00
d3babc62ff RestAPI merging. 2023-05-13 21:23:52 +04:00
aee700f1fb Frontend component views + api logic fixes. 2023-05-13 21:14:47 +04:00
e5eec7f4ca Guarantor: basic frontend views + logic fixes. 2023-05-13 18:23:36 +04:00
133 changed files with 77232 additions and 82 deletions

View File

@@ -13,6 +13,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ComputerStoreDatabaseImplem
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ComputerStoreRestAPI", "..\ComputerStoreRestAPI\ComputerStoreRestAPI.csproj", "{11E7B5B7-7AF5-4E1E-837F-E6645D3C0EFB}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ComputerStoreEmployeeApp", "..\ComputerStoreEmployeeApp\ComputerStoreEmployeeApp.csproj", "{E1091CF6-5350-402F-A305-2973C96D2AC5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -39,6 +41,10 @@ Global
{11E7B5B7-7AF5-4E1E-837F-E6645D3C0EFB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{11E7B5B7-7AF5-4E1E-837F-E6645D3C0EFB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{11E7B5B7-7AF5-4E1E-837F-E6645D3C0EFB}.Release|Any CPU.Build.0 = Release|Any CPU
{E1091CF6-5350-402F-A305-2973C96D2AC5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E1091CF6-5350-402F-A305-2973C96D2AC5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E1091CF6-5350-402F-A305-2973C96D2AC5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E1091CF6-5350-402F-A305-2973C96D2AC5}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@@ -0,0 +1,4 @@
@page
@model ComputerStoreEmployeeApp.Pages.ComponentMenuModel
@{
}

View File

@@ -0,0 +1,12 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace ComputerStoreEmployeeApp.Pages
{
public class ComponentMenuModel : PageModel
{
public void OnGet()
{
}
}
}

View File

@@ -5,6 +5,6 @@
}
<div class="text-center">
<h1 class="display-4">Welcome</h1>
<p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
<h1 class="display-4">ComputerStore"Ты же программист"</h1>
<p>This app was created for employees.</p>
</div>

View File

@@ -3,33 +3,52 @@
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - ComputerStore</title>
<title>@ViewData["Title"] - EmployeeApp</title>
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
<link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
<link rel="stylesheet" href="~/ComputerStore.styles.css" asp-append-version="true" />
</head>
<body>
<header>
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
<div class="container">
<a class="navbar-brand" asp-area="" asp-page="/Index">ComputerStore</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse" aria-controls="navbarSupportedContent"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
<ul class="navbar-nav flex-grow-1">
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/Index">Home</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/Privacy">Privacy</a>
</li>
</ul>
@if(ViewBag.ShowTopBar == false)
{
}
else
{
<header>
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
<div class="container">
<a class="navbar-brand" asp-area="" asp-page="/Index">EmployeeApp</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse" aria-controls="navbarSupportedContent"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
<ul class="navbar-nav flex-grow-1">
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/Index">Menu</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/ComponentMenu">Components</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/ProductMenu">Products</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/PCsMenu">PCs</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/Request">Requests</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/Report">Reports</a>
</li>
</ul>
</div>
</div>
</div>
</nav>
</header>
</nav>
</header>
}
<div class="container">
<main role="main" class="pb-3">
@RenderBody()
@@ -38,7 +57,7 @@
<footer class="border-top footer text-muted">
<div class="container">
&copy; 2023 - ComputerStore - <a asp-area="" asp-page="/Privacy">Privacy</a>
&copy; 2023 - ComputerStore - Privacy
</div>
</footer>

View File

@@ -133,9 +133,9 @@ namespace ComputerStoreBusinessLogic.BusinessLogic
}
public void SavePCsAndProductsToPdfFile(ReportDateBindingModel model)
public MemoryStream SavePCsAndProductsToPdfFile(ReportDateBindingModel model)
{
_saveToPDF.CreateDoc(new PDFInfo
return _saveToPDF.CreateDoc(new PDFInfo
{
FileName = model.FileName,
Title = "Products 'n orders list",

View File

@@ -35,6 +35,11 @@ namespace ComputerStoreBusinessLogic.BusinessLogic
public bool Update(ProductBindingModel model)
{
if(string.IsNullOrEmpty(model.Name))
{
model.Name = _productStorage.GetElement(new ProductSearchModel { ID = model.ID }).Name;
}
CheckModel(model);
if (_productStorage.Update(model) == null)
{

View File

@@ -37,7 +37,7 @@ namespace ComputerStoreBusinessLogic.MailStuff
_logger.LogDebug("Config: {login}, {password}, {clientHost}, {clientPort}, {popHost}, {popPort}", _mailLogin, _mailPassword, _smtpClientHost, _smtpClientPort, _popHost, _popPort);
}
public async void MailSendAsync(MailMessage info)
public async void MailSendAsync(string receiver, MemoryStream report)
{
if (string.IsNullOrEmpty(_mailLogin) || string.IsNullOrEmpty(_mailPassword))
{
@@ -47,14 +47,14 @@ namespace ComputerStoreBusinessLogic.MailStuff
{
return;
}
if (string.IsNullOrEmpty(info.To.ToString()) || string.IsNullOrEmpty(info.Subject) || string.IsNullOrEmpty(info.Body) || !info.Attachments.Any())
if (string.IsNullOrEmpty(receiver))
{
return;
}
_logger.LogDebug("Send E-mail: {To}, {Subject}", info.To.ToString(), info.Subject);
await SendMailAsync(info);
_logger.LogDebug("Send E-mail: {To}, {Subject}", receiver, "Report");
await SendMailAsync(receiver,report);
}
protected abstract Task SendMailAsync(MailMessage info);
protected abstract Task SendMailAsync(string receiver, MemoryStream report);
}
}

View File

@@ -4,6 +4,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Mail;
using System.Net.Mime;
using System.Text;
using System.Threading.Tasks;
@@ -15,17 +16,17 @@ namespace ComputerStoreBusinessLogic.MailStuff
{
}
protected override async Task SendMailAsync(MailMessage info)
protected override async Task SendMailAsync(string receiver, MemoryStream report)
{
using var objMailMessage = new MailMessage();
using var objSmtpClient = new SmtpClient(_smtpClientHost, _smtpClientPort);
try
{
objMailMessage.From = new MailAddress(_mailLogin);
objMailMessage.To.Add(new MailAddress(info.To.ToString()));
objMailMessage.Subject = info.Subject; objMailMessage.Body = info.Body;
objMailMessage.To.Add(new MailAddress(receiver));
objMailMessage.Subject = "Report";
objMailMessage.Attachments.Add(new Attachment(report, "ReportProductsPCs.pdf", "application/pdf"));
objMailMessage.SubjectEncoding = Encoding.UTF8;
objMailMessage.BodyEncoding = Encoding.UTF8;
objSmtpClient.UseDefaultCredentials = false;
objSmtpClient.EnableSsl = true;
objSmtpClient.DeliveryMethod = SmtpDeliveryMethod.Network;

View File

@@ -81,7 +81,7 @@ namespace ComputerStoreBusinessLogic.OfficePackage
{
ColumnName = "C",
RowIndex = rowIndex,
Text = consignment.ID.ToString(),
Text = consignment.Products.Count.ToString(),
StyleInfo = ExcelStyleInfoType.Text
});
rowIndex+=3;

View File

@@ -10,7 +10,7 @@ namespace ComputerStoreBusinessLogic.OfficePackage
{
public abstract class AbstractSaveToPDF
{
public void CreateDoc(PDFInfo info)
public MemoryStream CreateDoc(PDFInfo info)
{
CreatePDF(info);
CreateParagraph(new PDFParagraph
@@ -25,7 +25,7 @@ namespace ComputerStoreBusinessLogic.OfficePackage
Style = "Normal",
ParagraphAlignment = PDFParagraphAlignmentType.Center
});
CreateTable(new List<string> { "6cm", "6cm", "3cm", "5cm"});
CreateTable(new List<string> { "7cm", "3cm", "2cm", "5cm"});
CreateRow(new PDFRowParameters
{
Texts = new List<string> { "PC's name", "Employee's username", "Total", "Components" },
@@ -41,7 +41,7 @@ namespace ComputerStoreBusinessLogic.OfficePackage
ParagraphAlignment = PDFParagraphAlignmentType.Left
},pc.Components);
}
CreateTable(new List<string> { "6cm", "6cm", "3cm", "5cm" });
CreateTable(new List<string> { "7cm", "3cm", "2cm", "5cm" });
CreateRow(new PDFRowParameters
{
Texts = new List<string> { "Product's name", "Employee's username", "Total", "Components" },
@@ -59,7 +59,7 @@ namespace ComputerStoreBusinessLogic.OfficePackage
}
CreateParagraph(new PDFParagraph
{
Text = $"Total by products: {info.Products.Sum(x => x.Price)} + {info.Products}\t",
Text = $"Total by products: {info.Products.Sum(x => x.Price)}\t",
Style = "Normal",
ParagraphAlignment = PDFParagraphAlignmentType.Right
});
@@ -71,14 +71,14 @@ namespace ComputerStoreBusinessLogic.OfficePackage
});
CreateParagraph(new PDFParagraph
{
Text = $"Total: {info.PCs.Sum(x => x.Price)} + {info.Products.Sum(x => x.Price)}\t",
Text = $"Total: {info.PCs.Sum(x => x.Price) + info.Products.Sum(x => x.Price)}\t",
Style = "Normal",
ParagraphAlignment = PDFParagraphAlignmentType.Right
});
SavePDF(info);
return SavePDF(info);
}
protected abstract void SavePDF(PDFInfo info);
protected abstract MemoryStream SavePDF(PDFInfo info);
protected abstract void CreatePDF(PDFInfo info);
protected abstract void CreateParagraph(PDFParagraph PDFParagraph);
protected abstract void CreateTable(List<string> columns);

View File

@@ -15,8 +15,7 @@ namespace ComputerStoreBusinessLogic.OfficePackage.Implements
{
private Document? _document;
private Section? _section;
private Table? _table;
private Table? _table;
private static ParagraphAlignment GetParagraphAlignment(PDFParagraphAlignmentType type)
{
return type switch
@@ -134,15 +133,20 @@ namespace ComputerStoreBusinessLogic.OfficePackage.Implements
}
}
protected override void SavePDF(PDFInfo info)
protected override MemoryStream SavePDF(PDFInfo info)
{
var renderer = new PdfDocumentRenderer(true)
{
Document = _document
};
};
renderer.RenderDocument();
renderer.PdfDocument.Save(info.FileName);
MemoryStream mem = new MemoryStream();
renderer.PdfDocument.Save(mem,false);
mem.Seek(0, SeekOrigin.Begin);
return mem;
}
}
}

View File

@@ -0,0 +1,12 @@
{
"profiles": {
"ComputerStoreBusinessLogic": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "https://localhost:50448;http://localhost:50454"
}
}
}

View File

@@ -0,0 +1,23 @@
using ComputerStoreContracts.BindingModels;
using ComputerStoreContracts.ViewModels;
using ComputerStoreDataModels.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ComputerStoreContracts.APIModels
{
public class APIProductModel
{
public int ID { get; set; }
public string Name { get; set; } = string.Empty;
public double Price { get; set; }
public int EmployeeID { get; set; }
public Dictionary<int, (ComponentViewModel Component, int Quantity)> ProductComponents { get; set; } = new();
}
}

View File

@@ -1,9 +1,5 @@
using ComputerStoreDataModels.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace ComputerStoreContracts.BindingModels
{
@@ -15,7 +11,14 @@ namespace ComputerStoreContracts.BindingModels
public double Price { get; set; }
public int EmployeeID { get; set; }
public Dictionary<int, (IComponentModel Component, int Quantity)> ProductComponents { get; set; } = new();
public Dictionary<int, (IComponentModel, int)> ProductComponents { get; set; } = new();
[JsonConstructor]
public ProductBindingModel(Dictionary<int, (ComponentBindingModel Component, int Quantity)> ProductComponents)
{
this.ProductComponents = ProductComponents.ToDictionary(x => x.Key, x => (x.Value.Component as IComponentModel, x.Value.Quantity));
}
public ProductBindingModel() { }
}
}

View File

@@ -11,5 +11,6 @@ namespace ComputerStoreContracts.BindingModels
public string FileName { get; set; } = string.Empty;
public DateTime? DateFrom { get; set; }
public DateTime? DateTo { get; set;}
public string? Email { get; set; }
}
}

View File

@@ -14,7 +14,7 @@ namespace ComputerStoreContracts.BusinessLogicContracts
List<ReportPCByDateViewModel> GetPCsByDate(ReportDateBindingModel model);
List<ReportConsignmentsViewModel> GetConsignmentsByComponents(ReportComponentsBindingModel model);
void SavePCsAndProductsToPdfFile(ReportDateBindingModel model);
MemoryStream SavePCsAndProductsToPdfFile(ReportDateBindingModel model);
MemoryStream SaveConsignmentsToExcelFile(ReportComponentsBindingModel model);
MemoryStream SaveConsignmentsToWordFile(ReportComponentsBindingModel model);
}

View File

@@ -0,0 +1,12 @@
{
"profiles": {
"ComputerStoreContracts": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "https://localhost:50450;http://localhost:50453"
}
}
}

View File

@@ -1,8 +1,11 @@
using ComputerStoreDataModels.Models;
using ComputerStoreContracts.BindingModels;
using ComputerStoreDataModels.Models;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
@@ -23,8 +26,13 @@ namespace ComputerStoreContracts.ViewModels
[DisplayName("Employee's username")]
public string EmployeeUsername { get; set; } = string.Empty;
public Dictionary<int, (IComponentModel, int)> ProductComponents { get; set; } = new();
public Dictionary<int, (IComponentModel Component, int Quantity)> ProductComponents { get; set; } = new();
[JsonConstructor]
public ProductViewModel(Dictionary<int, (ComponentBindingModel Component, int Quantity)> ProductComponents)
{
this.ProductComponents = ProductComponents.ToDictionary(x => x.Key, x => (x.Value.Component as IComponentModel, x.Value.Quantity));
}
public ProductViewModel() { }
}
}

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
namespace ComputerStoreDataModels.Models

View File

@@ -11,6 +11,6 @@ namespace ComputerStoreDataModels.Models
public string Name { get; }
public double Price { get; }
public int EmployeeID { get; }
Dictionary<int,(IComponentModel,int)> ProductComponents { get; }
Dictionary<int,(IComponentModel Component, int Quantity)> ProductComponents { get; }
}
}

View File

@@ -0,0 +1,12 @@
{
"profiles": {
"ComputerStoreDataModels": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "https://localhost:50449;http://localhost:50452"
}
}
}

View File

@@ -7,8 +7,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.4" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.4" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.4">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
@@ -20,4 +20,8 @@
<ProjectReference Include="..\ComputerStoreDataModels\ComputerStoreDataModels.csproj" />
</ItemGroup>
<ItemGroup>
<Folder Include="Migrations\" />
</ItemGroup>
</Project>

View File

@@ -16,12 +16,18 @@ namespace ComputerStoreDatabaseImplement.Implements
public EmployeeViewModel? GetElement(EmployeeSearchModel model)
{
if(string.IsNullOrEmpty(model.Username) && !model.ID.HasValue)
if (string.IsNullOrEmpty(model.Username) && !model.ID.HasValue)
{
return null;
}
using var context = new ComputerStoreDatabase();
return context.Employees.FirstOrDefault(x => (!string.IsNullOrEmpty(model.Username) && model.Username == x.Username) || (model.ID.HasValue && model.ID == x.ID))?.GetViewModel;
if (!string.IsNullOrEmpty(model.Password))
{
return context.Employees.FirstOrDefault(user => model.Username.Equals(user.Username) && model.Password.Equals(user.Password))?.GetViewModel;
}
return context.Employees.FirstOrDefault(user => (!string.IsNullOrEmpty(model.Username) && model.Username.Equals(user.Username)) || (model.ID.HasValue && model.ID == user.ID))?.GetViewModel;
}
public List<EmployeeViewModel> GetFilteredList(EmployeeSearchModel model)

View File

@@ -37,7 +37,7 @@ namespace ComputerStoreDatabaseImplement.Implements
{
return context.PCS.Include(x => x.Employee).Include(x => x.Request).ThenInclude(x => x.PCs).ThenInclude(x => x.Component).Where(x => x.EmployeeID == model.EmployeeID).Select(x => x.GetViewModel).ToList();
}
return context.PCS.Include(x => x.Employee).Include(x => x.Request).ThenInclude(x => x.PCs).ThenInclude(x => x.Component).Where(p => context.Requests.Where(r => context.Orders.Where(o => o.DateCreate >= model.DateFrom && o.DateCreate <= model.DateTo).Select(o => o.ID).Contains(r.OrderID)).Select(r => r.ID).Contains(p.RequestID)).ToList().Select(x => x.GetViewModel).ToList();
return context.PCS.Include(x => x.Employee).Include(x => x.Request).ThenInclude(x => x.PCs).ThenInclude(x => x.Component).Include(x => x.Request).ThenInclude(x => x.Order).Where(x => x.Request != null && x.Request.Order.DateCreate >= model.DateFrom && x.Request.Order.DateCreate <= model.DateTo).Select(x => x.GetViewModel).ToList();
}
public List<PCViewModel> GetFullList()

View File

@@ -7,6 +7,7 @@ using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
@@ -19,7 +20,7 @@ namespace ComputerStoreDatabaseImplement.Implements
if(string.IsNullOrEmpty(model.Name) && !model.ID.HasValue) { return null; }
using var context = new ComputerStoreDatabase();
return context.Products.Include(x => x.Components).ThenInclude(x => x.Component).FirstOrDefault(x => (!string.IsNullOrEmpty(model.Name) && model.Name.Equals(x.Name)) || (model.ID.HasValue && model.ID == x.ID))?.GetViewModel;
return context.Products.Include(x => x.Employee).Include(x => x.Components).ThenInclude(x => x.Component).FirstOrDefault(x => (!string.IsNullOrEmpty(model.Name) && model.Name.Equals(x.Name)) || (model.ID.HasValue && model.ID == x.ID))?.GetViewModel;
}
public List<ProductViewModel> GetFilteredList(ProductSearchModel model)
@@ -36,15 +37,15 @@ namespace ComputerStoreDatabaseImplement.Implements
}
if(model.ComponentID.HasValue)
{
return context.Products.Include(x => x.Components).ThenInclude(x => x.Component).Where(p => context.ProductComponents.Where(pc => pc.ComponentID == model.ComponentID).Select(pc => pc.ProductID).Contains(p.ID)).Select(x => x.GetViewModel).ToList();
return context.Products.Include(x => x.Employee).Include(x => x.Components).ThenInclude(x => x.Component).Where(p => context.ProductComponents.Where(pc => pc.ComponentID == model.ComponentID).Select(pc => pc.ProductID).Contains(p.ID)).Select(x => x.GetViewModel).ToList();
}
return context.Products.Include(x => x.Components).ThenInclude(x => x.Component).Where(p => context.ConsignmentProducts.Where(cp => context.Consignments.Where(c => context.Orders.Where(o => o.DateCreate >= model.DateFrom && o.DateCreate <= model.DateTo).Select(o => o.ID).Contains(c.OrderID)).Select(c => c.ID).Contains(cp.ConsignmentID)).Select(cp => cp.ProductID).Contains(p.ID)).ToList().Select(x => x.GetViewModel).ToList();
return context.Products.Include(x => x.Employee).Include(x => x.Components).ThenInclude(x => x.Component).Include(x => x.Consignments).ThenInclude(x => x.Consignment).ThenInclude(x => x.Order).Where(x => x.Consignments.Count != 0 && x.Consignments.First().Consignment.Order.DateCreate >= model.DateFrom && x.Consignments.First().Consignment.Order.DateCreate <= model.DateTo).Select(x => x.GetViewModel).ToList();
}
public List<ProductViewModel> GetFullList()
{
using var context = new ComputerStoreDatabase();
return context.Products.Include(x => x.Components).ThenInclude(x => x.Component).ToList().Select(x => x.GetViewModel).ToList();
return context.Products.Include(x => x.Employee).Include(x => x.Components).ThenInclude(x => x.Component).ToList().Select(x => x.GetViewModel).ToList();
}
public ProductViewModel? Insert(ProductBindingModel model)
@@ -65,7 +66,7 @@ namespace ComputerStoreDatabaseImplement.Implements
using var transaction = context.Database.BeginTransaction();
try
{
var specProduct = context.Products.FirstOrDefault(x => x.ID==model.ID);
var specProduct = context.Products.Include(x => x.Employee).Include(x => x.Components).ThenInclude(x => x.Component).FirstOrDefault(x => x.ID==model.ID);
if(specProduct == null) { return null; }
specProduct.Update(model);
context.SaveChanges();
@@ -83,7 +84,7 @@ namespace ComputerStoreDatabaseImplement.Implements
public ProductViewModel? Delete(ProductBindingModel model)
{
using var context = new ComputerStoreDatabase();
var specProduct = context.Products.Include(x => x.Components).FirstOrDefault(x => x.ID == model.ID);
var specProduct = context.Products.Include(x => x.Employee).Include(x => x.Components).FirstOrDefault(x => x.ID == model.ID);
if(specProduct == null) { return null; }
context.Products.Remove(specProduct);

View File

@@ -0,0 +1,496 @@
// <auto-generated />
using System;
using ComputerStoreDatabaseImplement;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace ComputerStoreDatabaseImplement.Migrations
{
[DbContext(typeof(ComputerStoreDatabase))]
[Migration("20230517180637_NamingFixes")]
partial class NamingFixes
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "7.0.5")
.HasAnnotation("Relational:MaxIdentifierLength", 128);
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
modelBuilder.Entity("ComputerStoreDatabaseImplement.Models.Component", b =>
{
b.Property<int>("ID")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("ID"));
b.Property<string>("Name")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<double>("Price")
.HasColumnType("float");
b.HasKey("ID");
b.ToTable("Components");
});
modelBuilder.Entity("ComputerStoreDatabaseImplement.Models.Consignment", b =>
{
b.Property<int>("ID")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("ID"));
b.Property<int>("OrderID")
.HasColumnType("int");
b.Property<double>("Price")
.HasColumnType("float");
b.Property<int?>("ProductID")
.HasColumnType("int");
b.HasKey("ID");
b.HasIndex("OrderID");
b.HasIndex("ProductID");
b.ToTable("Consignments");
});
modelBuilder.Entity("ComputerStoreDatabaseImplement.Models.ConsignmentProduct", b =>
{
b.Property<int>("ID")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("ID"));
b.Property<int>("ConsignmentID")
.HasColumnType("int");
b.Property<int>("Count")
.HasColumnType("int");
b.Property<int>("ProductID")
.HasColumnType("int");
b.HasKey("ID");
b.HasIndex("ConsignmentID");
b.HasIndex("ProductID");
b.ToTable("ConsignmentProducts");
});
modelBuilder.Entity("ComputerStoreDatabaseImplement.Models.Employee", b =>
{
b.Property<int>("ID")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("ID"));
b.Property<string>("FirstName")
.HasColumnType("nvarchar(max)");
b.Property<string>("LastName")
.HasColumnType("nvarchar(max)");
b.Property<string>("MiddleName")
.HasColumnType("nvarchar(max)");
b.Property<string>("Password")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("Username")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.HasKey("ID");
b.ToTable("Employees");
});
modelBuilder.Entity("ComputerStoreDatabaseImplement.Models.Order", b =>
{
b.Property<int>("ID")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("ID"));
b.Property<DateTime>("DateCreate")
.HasColumnType("datetime2");
b.Property<DateTime?>("DateImplement")
.HasColumnType("datetime2");
b.Property<double>("Price")
.HasColumnType("float");
b.Property<int>("SellerID")
.HasColumnType("int");
b.Property<int>("Status")
.HasColumnType("int");
b.HasKey("ID");
b.HasIndex("SellerID");
b.ToTable("Orders");
});
modelBuilder.Entity("ComputerStoreDatabaseImplement.Models.PC", b =>
{
b.Property<int>("ID")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("ID"));
b.Property<int>("EmployeeID")
.HasColumnType("int");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<double>("Price")
.HasColumnType("float");
b.Property<int>("RequestID")
.HasColumnType("int");
b.HasKey("ID");
b.HasIndex("EmployeeID");
b.ToTable("PCS");
});
modelBuilder.Entity("ComputerStoreDatabaseImplement.Models.Product", b =>
{
b.Property<int>("ID")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("ID"));
b.Property<int>("EmployeeID")
.HasColumnType("int");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<double>("Price")
.HasColumnType("float");
b.HasKey("ID");
b.HasIndex("EmployeeID");
b.ToTable("Products");
});
modelBuilder.Entity("ComputerStoreDatabaseImplement.Models.ProductComponent", b =>
{
b.Property<int>("ID")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("ID"));
b.Property<int>("ComponentID")
.HasColumnType("int");
b.Property<int>("Count")
.HasColumnType("int");
b.Property<int>("ProductID")
.HasColumnType("int");
b.HasKey("ID");
b.HasIndex("ComponentID");
b.HasIndex("ProductID");
b.ToTable("ProductComponents");
});
modelBuilder.Entity("ComputerStoreDatabaseImplement.Models.Request", b =>
{
b.Property<int>("ID")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("ID"));
b.Property<int>("OrderID")
.HasColumnType("int");
b.Property<int?>("PCID")
.HasColumnType("int");
b.Property<double>("Price")
.HasColumnType("float");
b.HasKey("ID");
b.HasIndex("OrderID");
b.ToTable("Requests");
});
modelBuilder.Entity("ComputerStoreDatabaseImplement.Models.RequestComponent", b =>
{
b.Property<int>("ID")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("ID"));
b.Property<int>("ComponentID")
.HasColumnType("int");
b.Property<int>("Count")
.HasColumnType("int");
b.Property<int?>("PCID")
.HasColumnType("int");
b.Property<int>("RequestID")
.HasColumnType("int");
b.HasKey("ID");
b.HasIndex("ComponentID");
b.HasIndex("PCID");
b.HasIndex("RequestID");
b.ToTable("RequestComponents");
});
modelBuilder.Entity("ComputerStoreDatabaseImplement.Models.Seller", b =>
{
b.Property<int>("ID")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("ID"));
b.Property<string>("FirstName")
.HasColumnType("nvarchar(max)");
b.Property<string>("LastName")
.HasColumnType("nvarchar(max)");
b.Property<string>("MiddleName")
.HasColumnType("nvarchar(max)");
b.Property<string>("Password")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("Username")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.HasKey("ID");
b.ToTable("Sellers");
});
modelBuilder.Entity("ComputerStoreDatabaseImplement.Models.Consignment", b =>
{
b.HasOne("ComputerStoreDatabaseImplement.Models.Order", "Order")
.WithMany("_consignments")
.HasForeignKey("OrderID")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("ComputerStoreDatabaseImplement.Models.Product", null)
.WithMany("Consignments")
.HasForeignKey("ProductID");
b.Navigation("Order");
});
modelBuilder.Entity("ComputerStoreDatabaseImplement.Models.ConsignmentProduct", b =>
{
b.HasOne("ComputerStoreDatabaseImplement.Models.Consignment", "Consignment")
.WithMany("Products")
.HasForeignKey("ConsignmentID")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("ComputerStoreDatabaseImplement.Models.Product", "Product")
.WithMany()
.HasForeignKey("ProductID")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Consignment");
b.Navigation("Product");
});
modelBuilder.Entity("ComputerStoreDatabaseImplement.Models.Order", b =>
{
b.HasOne("ComputerStoreDatabaseImplement.Models.Seller", "Seller")
.WithMany("Orders")
.HasForeignKey("SellerID")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Seller");
});
modelBuilder.Entity("ComputerStoreDatabaseImplement.Models.PC", b =>
{
b.HasOne("ComputerStoreDatabaseImplement.Models.Employee", "Employee")
.WithMany("PCs")
.HasForeignKey("EmployeeID")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Employee");
});
modelBuilder.Entity("ComputerStoreDatabaseImplement.Models.Product", b =>
{
b.HasOne("ComputerStoreDatabaseImplement.Models.Employee", "Employee")
.WithMany("Products")
.HasForeignKey("EmployeeID")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Employee");
});
modelBuilder.Entity("ComputerStoreDatabaseImplement.Models.ProductComponent", b =>
{
b.HasOne("ComputerStoreDatabaseImplement.Models.Component", "Component")
.WithMany("ConsignmentComponents")
.HasForeignKey("ComponentID")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("ComputerStoreDatabaseImplement.Models.Product", "Product")
.WithMany("Components")
.HasForeignKey("ProductID")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Component");
b.Navigation("Product");
});
modelBuilder.Entity("ComputerStoreDatabaseImplement.Models.Request", b =>
{
b.HasOne("ComputerStoreDatabaseImplement.Models.Order", "Order")
.WithMany("_requests")
.HasForeignKey("OrderID")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Order");
});
modelBuilder.Entity("ComputerStoreDatabaseImplement.Models.RequestComponent", b =>
{
b.HasOne("ComputerStoreDatabaseImplement.Models.Component", "Component")
.WithMany("RequestComponents")
.HasForeignKey("ComponentID")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("ComputerStoreDatabaseImplement.Models.PC", "PC")
.WithMany("Components")
.HasForeignKey("PCID");
b.HasOne("ComputerStoreDatabaseImplement.Models.Request", "Request")
.WithMany("PCs")
.HasForeignKey("RequestID")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Component");
b.Navigation("PC");
b.Navigation("Request");
});
modelBuilder.Entity("ComputerStoreDatabaseImplement.Models.Component", b =>
{
b.Navigation("ConsignmentComponents");
b.Navigation("RequestComponents");
});
modelBuilder.Entity("ComputerStoreDatabaseImplement.Models.Consignment", b =>
{
b.Navigation("Products");
});
modelBuilder.Entity("ComputerStoreDatabaseImplement.Models.Employee", b =>
{
b.Navigation("PCs");
b.Navigation("Products");
});
modelBuilder.Entity("ComputerStoreDatabaseImplement.Models.Order", b =>
{
b.Navigation("_consignments");
b.Navigation("_requests");
});
modelBuilder.Entity("ComputerStoreDatabaseImplement.Models.PC", b =>
{
b.Navigation("Components");
});
modelBuilder.Entity("ComputerStoreDatabaseImplement.Models.Product", b =>
{
b.Navigation("Components");
b.Navigation("Consignments");
});
modelBuilder.Entity("ComputerStoreDatabaseImplement.Models.Request", b =>
{
b.Navigation("PCs");
});
modelBuilder.Entity("ComputerStoreDatabaseImplement.Models.Seller", b =>
{
b.Navigation("Orders");
});
#pragma warning restore 612, 618
}
}
}

View File

@@ -0,0 +1,100 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace ComputerStoreDatabaseImplement.Migrations
{
/// <inheritdoc />
public partial class NamingFixes : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_PCs_Employees_EmployeeID",
table: "PCs");
migrationBuilder.DropForeignKey(
name: "FK_RequestComponents_PCs_PCID",
table: "RequestComponents");
migrationBuilder.DropPrimaryKey(
name: "PK_PCs",
table: "PCs");
migrationBuilder.RenameTable(
name: "PCs",
newName: "PCS");
migrationBuilder.RenameIndex(
name: "IX_PCs_EmployeeID",
table: "PCS",
newName: "IX_PCS_EmployeeID");
migrationBuilder.AddPrimaryKey(
name: "PK_PCS",
table: "PCS",
column: "ID");
migrationBuilder.AddForeignKey(
name: "FK_PCS_Employees_EmployeeID",
table: "PCS",
column: "EmployeeID",
principalTable: "Employees",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "FK_RequestComponents_PCS_PCID",
table: "RequestComponents",
column: "PCID",
principalTable: "PCS",
principalColumn: "ID");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_PCS_Employees_EmployeeID",
table: "PCS");
migrationBuilder.DropForeignKey(
name: "FK_RequestComponents_PCS_PCID",
table: "RequestComponents");
migrationBuilder.DropPrimaryKey(
name: "PK_PCS",
table: "PCS");
migrationBuilder.RenameTable(
name: "PCS",
newName: "PCs");
migrationBuilder.RenameIndex(
name: "IX_PCS_EmployeeID",
table: "PCs",
newName: "IX_PCs_EmployeeID");
migrationBuilder.AddPrimaryKey(
name: "PK_PCs",
table: "PCs",
column: "ID");
migrationBuilder.AddForeignKey(
name: "FK_PCs_Employees_EmployeeID",
table: "PCs",
column: "EmployeeID",
principalTable: "Employees",
principalColumn: "ID",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "FK_RequestComponents_PCs_PCID",
table: "RequestComponents",
column: "PCID",
principalTable: "PCs",
principalColumn: "ID");
}
}
}

View File

@@ -1,6 +1,7 @@
using ComputerStoreContracts.BindingModels;
using ComputerStoreContracts.ViewModels;
using ComputerStoreDataModels.Models;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
@@ -26,7 +27,7 @@ namespace ComputerStoreDatabaseImplement.Models
public int EmployeeID { get; private set; }
private Dictionary<int, (IComponentModel, int)>? _productComponents = null;
private Dictionary<int, (IComponentModel Component, int Quantity)>? _productComponents = null;
[NotMapped]
public Dictionary<int, (IComponentModel, int)> ProductComponents
@@ -40,10 +41,10 @@ namespace ComputerStoreDatabaseImplement.Models
return _productComponents;
}
}
[ForeignKey("ProductID")]
public virtual List<ProductComponent> Components { get; set; } = new();
[ForeignKey("ProductID")]
public virtual List<ConsignmentProduct> Consignments { get; set; } = new();
@@ -56,6 +57,7 @@ namespace ComputerStoreDatabaseImplement.Models
Name = model.Name,
Price = model.Price,
EmployeeID = model.EmployeeID,
Employee = context.Employees.First(x => x.ID == model.EmployeeID),
Components = model.ProductComponents.Select(x => new ProductComponent
{
Component = context.Components.First(y => y.ID == x.Key),

View File

@@ -8,7 +8,6 @@ using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Azure.Core;
using ComputerStoreContracts.SearchModels;
using Microsoft.EntityFrameworkCore;
using System.Xml.Linq;

View File

@@ -0,0 +1,12 @@
{
"profiles": {
"ComputerStoreDatabaseImplement": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "https://localhost:50447;http://localhost:50451"
}
}
}

View File

@@ -0,0 +1,102 @@
using ComputerStoreContracts.BindingModels;
using ComputerStoreContracts.ViewModels;
using ComputerStoreDataModels.Models;
using Microsoft.VisualBasic;
using Newtonsoft.Json;
using System.Net;
using System.Net.Http.Headers;
using System.Text;
namespace ComputerStoreEmployeeApp
{
public class APIClient
{
private static readonly HttpClient _client = new();
public static EmployeeViewModel? Employee { get; set; } = null;
public static Dictionary<int, (IComponentModel Component, int Quantity)>? productComponents;
public static Dictionary<int, (IComponentModel Component, int Quantity)>? pcComponents;
public static void Connect(IConfiguration configuration)
{
_client.BaseAddress = new Uri(configuration["IPAddress"]);
_client.DefaultRequestHeaders.Accept.Clear();
_client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
}
public static async Task<T?> GetRequest<T>(string requestUrl)
{
var response = await _client.GetAsync(requestUrl);
var result = response.Content.ReadAsStringAsync().Result;
if (response.IsSuccessStatusCode)
{
return JsonConvert.DeserializeObject<T>(result);
}
else
{
throw new Exception(result);
}
}
public static Stream GetRequestFile<T>(string requestUrl, ReportComponentsBindingModel model)
{
var json = JsonConvert.SerializeObject(model);
var data = new StringContent(json, Encoding.UTF8, "application/json");
var response = _client.PostAsync(requestUrl, data).Result;
if (response.StatusCode == HttpStatusCode.OK)
{
response.Content.Headers.TryGetValues("content-type", out var type);
return response.Content.ReadAsStreamAsync().Result;
}
else
{
throw new Exception("Something went wrong!");
}
}
public static async Task<bool> PostRequest<T>(string requestUrl, T model)
{
var json = JsonConvert.SerializeObject(model);
var data = new StringContent(json, Encoding.UTF8, "application/json");
var response = await _client.PostAsync(requestUrl, data);
var result = response.Content.ReadAsStringAsync().Result;
if (!response.IsSuccessStatusCode)
{
throw new Exception(result);
}
return true;
}
public static async Task<bool> PatchRequest<T>(string requestUrl, T model)
{
var json = JsonConvert.SerializeObject(model);
var data = new StringContent(json, Encoding.UTF8, "application/json-patch+json");
var response = await _client.PatchAsync(requestUrl, data);
var result = response.Content.ReadAsStringAsync().Result;
if (!response.IsSuccessStatusCode)
{
throw new Exception(result);
}
return Convert.ToBoolean(result);
}
public static async Task<bool> DeleteRequest<T>(string requestUrl)
{
var response = await _client.DeleteAsync(requestUrl);
var result = response.Content.ReadAsStringAsync().Result;
if (!response.IsSuccessStatusCode)
{
throw new Exception(result);
}
return Convert.ToBoolean(result);
}
}
}

View File

@@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNet.Mvc" Version="5.2.9" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.5">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ComputerStoreContracts\ComputerStoreContracts.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,623 @@
using ComputerStoreContracts.APIModels;
using ComputerStoreContracts.BindingModels;
using ComputerStoreContracts.ViewModels;
using ComputerStoreDataModels.Models;
using ComputerStoreEmployeeApp.Models;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
namespace ComputerStoreEmployeeApp.Controllers
{
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
public HomeController(ILogger<HomeController> logger)
{
_logger = logger;
}
public IActionResult Index()
{
if (APIClient.Employee == null) { return Redirect("Home/Enter"); }
return View();
}
public IActionResult ComponentMenu()
{
return View();
}
public IActionResult ComponentAdd()
{
return View();
}
[HttpPost]
public IActionResult ComponentAdd(string componentname, double componentprice)
{
try
{
if (string.IsNullOrEmpty(componentname) || string.IsNullOrEmpty(componentprice.ToString()))
{
throw new Exception("Enter component's name and price.");
}
if (!Task.Run(() => APIClient.PostRequest("api/main/insertcomponent", new ComponentBindingModel
{
Name = componentname,
Price = componentprice
})).Result)
{
throw new InvalidOperationException("Component with such name already exists");
}
}
catch (Exception ex)
{
ViewBag.Message = new string(ex.Message.ToString());
return View();
}
return Redirect("ComponentMenu");
}
[HttpGet]
public IActionResult ComponentUpdate()
{
ViewBag.Components = APIClient.GetRequest<List<ComponentViewModel>>("api/main/getcomponentslist").Result;
if (ViewBag.Components.Count == 0)
{
ViewBag.Message = "There are no components.";
return View("ComponentMenu");
}
return View();
}
[HttpPost]
public IActionResult ComponentUpdate(int component, string? componentname, double? componentprice)
{
try
{
if (string.IsNullOrEmpty(componentname) && !componentprice.HasValue)
{
throw new Exception("Enter at least one field.");
}
if (string.IsNullOrEmpty(componentname))
{
Task.Run(() => APIClient.PatchRequest("api/main/updatecomponent", new ComponentBindingModel
{
ID = component,
Price = componentprice.Value
}));
}
else if (!componentprice.HasValue)
{
Task.Run(() => APIClient.PatchRequest("api/main/updatecomponent", new ComponentBindingModel
{
ID = component,
Name = componentname
}));
}
else
{
Task.Run(() => APIClient.PatchRequest("api/main/updatecomponent", new ComponentBindingModel
{
ID = component,
Name = componentname,
Price = componentprice.Value
}));
}
}
catch (Exception ex)
{
ViewBag.Message = new string(ex.Message.ToString());
return View();
}
return Redirect("ComponentMenu");
}
[HttpGet]
public IActionResult ComponentDelete()
{
ViewBag.Components = APIClient.GetRequest<List<ComponentViewModel>>("api/main/getcomponentslist").Result;
if(ViewBag.Components.Count == 0)
{
ViewBag.Message = "There are no components.";
return View("ComponentMenu");
}
return View();
}
[HttpPost]
public IActionResult ComponentDelete(int component)
{
try
{
Task.Run(() => APIClient.DeleteRequest<string>($"api/main/deletecomponent/{component}"));
}
catch (Exception ex)
{
ViewBag.Message = new string(ex.Message.ToString());
return View();
}
return Redirect("ComponentMenu");
}
[HttpGet]
public IActionResult ComponentCheck()
{
return View(APIClient.GetRequest<List<ComponentViewModel>>("api/main/getcomponentslist").Result);
}
[HttpGet]
public IActionResult ProductMenu()
{
APIClient.productComponents = new Dictionary<int, (IComponentModel Component, int Quantity)>();
return View();
}
[HttpGet]
public IActionResult ProductAdd()
{
ViewBag.Components = APIClient.GetRequest<List<ComponentViewModel>>("api/main/getcomponentslist").Result;
if (ViewBag.Components.Count == 0)
{
ViewBag.Message = "There are no components.";
return View("ComponentMenu");
}
return View(APIClient.productComponents);
}
[HttpPost]
public IActionResult ProductAdd(string productname, double productprice)
{
try
{
if (string.IsNullOrEmpty(productname) || string.IsNullOrEmpty(productprice.ToString()))
{
throw new Exception("Enter product's name or product doesn't have any components.");
}
if (!Task.Run(() => APIClient.PostRequest("api/main/insertproduct", new ProductBindingModel
{
Name = productname,
Price = productprice,
EmployeeID = APIClient.Employee.ID,
ProductComponents = APIClient.productComponents
})).Result)
{
throw new InvalidOperationException("Product with such name already exists");
}
}
catch (Exception ex)
{
APIClient.productComponents.Clear();
ViewBag.Message = new string(ex.Message.ToString());
ViewBag.Components = APIClient.GetRequest<List<ComponentViewModel>>("api/main/getcomponentslist").Result;
return View(APIClient.productComponents);
}
APIClient.productComponents.Clear();
return Redirect("ProductMenu");
}
[HttpPost]
public double ProductComponents(int id, int componentquantity)
{
var component = APIClient.GetRequest<ComponentViewModel>($"api/main/getcomponent?id={id}").Result;
if (APIClient.productComponents.ContainsKey(component.ID))
{
APIClient.productComponents[component.ID] = (component, componentquantity);
}
else
{
APIClient.productComponents.Add(component.ID, (component, componentquantity));
}
return APIClient.productComponents.Sum(x => x.Value.Component.Price * x.Value.Quantity);
}
[HttpGet("/Home/ProductUpdate/{id}")]
public IActionResult ProductUpdate(int? id, bool selectChange = false)
{
ViewBag.Components = APIClient.GetRequest<List<ComponentViewModel>>("api/main/getcomponentslist").Result;
var list = APIClient.GetRequest<List<ProductViewModel>>("api/main/getproductslist").Result;
if(!list.Any())
{
ViewBag.Message = "There are no products.";
return View("ProductMenu");
}
ViewBag.Products = list;
if (!id.HasValue)
{
var product = list.First();
APIClient.productComponents = product.ProductComponents;
ViewBag.Price = product.Price;
return View(APIClient.productComponents);
}
ViewBag.ID = id;
if (selectChange)
{
var specproduct = list.First(x => x.ID == id);
APIClient.productComponents = specproduct.ProductComponents;
ViewBag.Price = specproduct.Price;
return View(specproduct.ProductComponents);
}
ViewBag.Price = APIClient.productComponents.Sum(x => x.Value.Component.Price * x.Value.Quantity);
return View(APIClient.productComponents);
}
[HttpPost]
public IActionResult ProductUpdate(int id, double productprice, string? productname)
{
try
{
if (!Task.Run(() => APIClient.PatchRequest("api/main/updateproduct", new ProductBindingModel
{
ID = id,
Name = productname,
Price = productprice,
EmployeeID = APIClient.Employee.ID,
ProductComponents = APIClient.productComponents.Where(component => component.Value.Quantity != 0).ToDictionary(x => x.Key, x => (x.Value.Component as IComponentModel, x.Value.Quantity))
})).Result)
{
throw new InvalidOperationException("Something went wrong.");
}
}
catch (Exception ex)
{
APIClient.productComponents.Clear();
ViewBag.Message = new string(ex.Message.ToString());
ViewBag.Components = APIClient.GetRequest<List<ComponentViewModel>>("api/main/getcomponentslist").Result;
return View(APIClient.productComponents);
}
APIClient.productComponents.Clear();
return Redirect("ProductMenu");
}
[HttpGet]
public IActionResult ProductDelete()
{
ViewBag.Products = APIClient.GetRequest<List<ProductViewModel>>("api/main/getproductslist").Result;
if (ViewBag.Products.Count == 0)
{
ViewBag.Message = "There are no products.";
return View("ProductMenu");
}
return View();
}
[HttpPost]
public IActionResult ProductDelete(int product)
{
try
{
Task.Run(() => APIClient.DeleteRequest<string>($"api/main/deleteproduct/{product}"));
}
catch (Exception ex)
{
ViewBag.Message = new string(ex.Message.ToString());
return View();
}
return Redirect("ProductMenu");
}
[HttpGet]
public IActionResult ProductCheck()
{
return View(APIClient.GetRequest<List<ProductViewModel>>("api/main/getproductslist").Result);
}
[HttpGet]
public IActionResult PCMenu()
{
APIClient.pcComponents = new Dictionary<int, (IComponentModel Component, int Quantity)>();
return View();
}
[HttpGet]
public IActionResult PCAdd(int? request)
{
ViewBag.Components = APIClient.GetRequest<List<ComponentViewModel>>("api/main/getcomponentslist").Result;
if(!APIClient.GetRequest<List<RequestComponentViewModel>>($"api/main/getrequestcomponentlist?id={null}").Result.Any())
{
ViewBag.Message = "There are no active reqeusts";
return View("PCMenu");
}
ViewBag.Requests = APIClient.GetRequest<List<RequestComponentViewModel>>($"api/main/getrequestcomponentlist?id={null}").Result.Select(x => new RequestViewModel { ID = x.RequestID}).GroupBy(x => x.ID).Select(x => x.First()).ToList();
ViewBag.PCComponents = APIClient.pcComponents;
if(request == null)
{
ViewBag.ID = ViewBag.Requests[0].ID;
}
else
{
ViewBag.ID = request;
}
return View(Requests(request));
}
public List<RequestComponentViewModel> Requests(int? id)
{
if (id == null)
{
var wholelist = APIClient.GetRequest<List<RequestComponentViewModel>>($"api/main/getrequestcomponentlist?id={null}").Result;
ViewBag.Requests = APIClient.GetRequest<List<RequestComponentViewModel>>($"api/main/getrequestcomponentlist?id={null}").Result.Select(x => new RequestViewModel { ID = x.RequestID }).GroupBy(x => x.ID).Select(x => x.First()).ToList();
var componentsList = wholelist.Where(x => x.RequestID == ViewBag.Requests[0].ID).Select(x => new RequestComponentViewModel { ComponentName = x.ComponentName, ComponentCount = x.ComponentCount }).ToList();
return componentsList;
}
var speclist = APIClient.GetRequest<List<RequestComponentViewModel>>($"api/main/getrequestcomponentlist?id={id}").Result;
var specificcomponentList = speclist.Where(x => x.RequestID == id).Select(x => new RequestComponentViewModel { ComponentName = x.ComponentName, ComponentCount = x.ComponentCount }).ToList();
return specificcomponentList;
}
[HttpPost]
public IActionResult PCAdd(string pcname, double pcprice, int request)
{
try
{
if (string.IsNullOrEmpty(pcname) || string.IsNullOrEmpty(pcprice.ToString()))
{
throw new Exception("Enter pc's name or pc doesn't have any components.");
}
if (!APIClient.PostRequest("api/main/insertpc",new PCBindingModel
{
Name = pcname,
Price = pcprice,
EmployeeID = APIClient.Employee.ID,
RequestID = request,
PCComponents = APIClient.pcComponents
}).Result)
{
throw new InvalidOperationException("PC with such name already exists");
}
}
catch (Exception ex)
{
APIClient.pcComponents.Clear();
ViewBag.Message = new string(ex.Message.ToString());
ViewBag.Components = APIClient.GetRequest<List<ComponentViewModel>>("api/main/getcomponentslist").Result;
ViewBag.Requests = APIClient.GetRequest<List<RequestViewModel>>($"api/main/getrequestlist?id={null}").Result;
ViewBag.PCComponents = APIClient.pcComponents;
return View(Requests(request));
}
APIClient.pcComponents.Clear();
return Redirect("PCMenu");
}
[HttpPost]
public double PCComponents(int id, int componentquantity)
{
var component = APIClient.GetRequest<ComponentViewModel>($"api/main/getcomponent?id={id}").Result;
if (APIClient.pcComponents.ContainsKey(component.ID))
{
APIClient.pcComponents[component.ID] = (component, componentquantity);
}
else
{
APIClient.pcComponents.Add(component.ID, (component, componentquantity));
}
return APIClient.pcComponents.Sum(x => x.Value.Component.Price * x.Value.Quantity);
}
[HttpGet("/Home/PCUpdate/{id}")]
public IActionResult PCUpdate(int? id, bool selectChange = false)
{
ViewBag.Components = APIClient.GetRequest<List<ComponentViewModel>>("api/main/getcomponentslist").Result;
var list = APIClient.GetRequest<List<PCViewModel>>("api/main/getpcslist").Result;
if (!list.Any())
{
ViewBag.Message = "There are no products.";
return View("PCMenu");
}
ViewBag.PCs = list;
if (!id.HasValue)
{
var pc = list.First();
APIClient.pcComponents = pc.PCComponents;
ViewBag.Price = pc.Price;
return View(APIClient.pcComponents);
}
ViewBag.ID = id;
if (selectChange)
{
var specpc = list.First(x => x.ID == id);
APIClient.pcComponents = specpc.PCComponents;
ViewBag.Price = specpc.Price;
return View(specpc.PCComponents);
}
ViewBag.Price = APIClient.pcComponents.Sum(x => x.Value.Component.Price * x.Value.Quantity);
return View(APIClient.pcComponents);
}
[HttpPost]
public IActionResult PCUpdate(int id, double pcprice, string? pcname)
{
try
{
if (!Task.Run(() => APIClient.PatchRequest("api/main/updatepc", new PCBindingModel
{
ID = id,
Name = pcname,
Price = pcprice,
EmployeeID = APIClient.Employee.ID,
PCComponents = APIClient.pcComponents.Where(component => component.Value.Quantity != 0).ToDictionary(x => x.Key, x => (x.Value.Component as IComponentModel, x.Value.Quantity))
})).Result)
{
throw new InvalidOperationException("Something went wrong.");
}
}
catch (Exception ex)
{
APIClient.pcComponents.Clear();
ViewBag.Message = new string(ex.Message.ToString());
ViewBag.Components = APIClient.GetRequest<List<ComponentViewModel>>("api/main/getcomponentslist").Result;
return View(APIClient.pcComponents);
}
APIClient.pcComponents.Clear();
return Redirect("PCMenu");
}
[HttpGet]
public IActionResult PCDelete()
{
ViewBag.PCs = APIClient.GetRequest<List<PCViewModel>>("api/main/getpcslist").Result;
if (ViewBag.PCs.Count == 0)
{
ViewBag.Message = "There are no PCs.";
return View("PCMenu");
}
return View();
}
[HttpPost]
public IActionResult PCDelete(int pc)
{
try
{
Task.Run(() => APIClient.DeleteRequest<string>($"api/main/deletepc/{pc}"));
}
catch (Exception ex)
{
ViewBag.Message = new string(ex.Message.ToString());
return View();
}
return Redirect("PCMenu");
}
[HttpGet]
public IActionResult PCCheck()
{
return View(APIClient.GetRequest<List<PCViewModel>>("api/main/getpcslist").Result);
}
[HttpGet]
public IActionResult Register()
{
ViewBag.ShowTopBar = false;
return View();
}
[HttpPost]
public IActionResult Register(string username, string password, string? firstname, string? middlename,string? lastname)
{
try
{
if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password))
{
throw new Exception("Enter login and password.");
}
Task.Run(() => APIClient.PostRequest("api/employee/register", new EmployeeBindingModel
{
Username = username,
Password = password,
FirstName = firstname != null ? firstname : null,
MiddleName = middlename != null ? middlename : null,
LastName = lastname != null ? lastname : null
}));
}
catch (Exception ex)
{
ViewBag.Message = new string(ex.Message.ToString());
ViewBag.ShowTopBar = false;
return View();
}
return Redirect("Enter");
}
[HttpGet]
public IActionResult Enter()
{
ViewBag.ShowTopBar = false;
return View();
}
[HttpPost]
public IActionResult Enter(string login, string password)
{
try
{
if (string.IsNullOrEmpty(login) || string.IsNullOrEmpty(password)) { throw new Exception("Enter login and password"); }
APIClient.Employee = APIClient.GetRequest<EmployeeViewModel>($"api/employee/login?login={login}&password={password}").Result;
if (APIClient.Employee == null) { throw new Exception("Incorrect login/password"); }
}
catch (Exception ex)
{
ViewBag.Message = new string(ex.Message.ToString());
ViewBag.ShowTopBar = false;
return View();
}
return Redirect("Index");
}
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
}
}

View File

@@ -0,0 +1,137 @@
using ComputerStoreContracts.BindingModels;
using ComputerStoreContracts.SearchModels;
using ComputerStoreContracts.ViewModels;
using ComputerStoreDataModels.Models;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ComputerStoreEmployeeApp.Controllers
{
public class ReportController : Controller
{
private readonly ILogger<ReportController> _logger;
public ReportController(ILogger<ReportController> logger)
{
_logger = logger;
}
public IActionResult ReportMenu()
{
APIClient.productComponents = new();
return View();
}
public IActionResult ConsignmentsReport()
{
ViewBag.Components = APIClient.GetRequest<List<ComponentViewModel>>("api/main/getcomponentslist").Result;
return View(APIClient.productComponents);
}
[HttpPost]
public IActionResult SaveExcel()
{
var model = new ReportComponentsBindingModel
{
FileName = "ReportConsignments.xlsx",
Components = APIClient.productComponents.Select(x => new ComponentSearchModel { ID = x.Key, Name = x.Value.Component.Name }).ToList()
};
var mem = APIClient.GetRequestFile<ReportComponentsBindingModel>($"api/main/savereportconsignmentstoexcel", model);
return File(mem,
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"ReportConsignments.xlsx");
}
[HttpPost]
public IActionResult SaveWord()
{
var model = new ReportComponentsBindingModel
{
FileName = "ReportConsignments.doc",
Components = APIClient.productComponents.Select(x => new ComponentSearchModel { ID = x.Key, Name = x.Value.Component.Name }).ToList()
};
var mem = APIClient.GetRequestFile<ReportComponentsBindingModel>($"api/main/savereportconsignmentstoword", model);
return File(mem,
"application/vnd.openxmlformats-officedocument.spreadsheetml.document",
"ReportConsignments.doc");
}
[HttpPost]
public void ConsignmentComponents(int id)
{
var component = APIClient.GetRequest<ComponentViewModel>($"api/main/getcomponent?id={id}").Result;
if (APIClient.productComponents.ContainsKey(component.ID))
{
APIClient.productComponents[component.ID] = (component, 1);
}
else
{
APIClient.productComponents.Add(component.ID, (component, 1));
}
}
[HttpGet]
public IActionResult ConsignmentsReportResult()
{
if (APIClient.productComponents.Any())
{
var str = ModelToStr();
ViewBag.Consignments = APIClient.GetRequest<List<ReportConsignmentsViewModel>>($"api/main/GetReportConsignments?str={str}").Result;
return View("ConsignmentsReport", APIClient.productComponents);
}
ViewBag.Message = "You should enter at least one product";
ViewBag.Components = APIClient.GetRequest<List<ComponentViewModel>>("api/main/getcomponentslist").Result;
return View("ConsignmentsReport", APIClient.productComponents);
}
public string ModelToStr()
{
StringBuilder stringBuilder = new StringBuilder();
foreach (var component in APIClient.productComponents)
{
stringBuilder.Append($"{component.Key}|{component.Value.Component.Name};");
}
var str = stringBuilder.ToString();
return str;
}
public IActionResult PCsProductsReport()
{
return View();
}
[HttpGet]
public IActionResult PCsProductsReportResult(DateTime? fromdate, DateTime? todate)
{
ViewBag.Search = true;
ViewBag.Products = APIClient.GetRequest<List<ReportProductByDateViewModel>>($"api/main/GetProductsByDate?From={fromdate}&To={todate}").Result;
ViewBag.PCs = APIClient.GetRequest<List<ReportPCByDateViewModel>>($"api/main/GetPCsByDate?From={fromdate}&To={todate}").Result;
return View("PCsProductsReport");
}
public IActionResult SendEmail(string? email, DateTime? datefrom, DateTime? dateto)
{
if(string.IsNullOrEmpty(email))
{
return Redirect("ReportMenu");
}
Task.Run(() => APIClient.PostRequest($"api/main/SendPDFtoEmail", new ReportDateBindingModel { FileName = "ReportProductsPCs", DateFrom = datefrom, DateTo = dateto, Email = email }));
return Redirect("ReportMenu");
}
}
}

View File

@@ -0,0 +1,9 @@
namespace ComputerStoreEmployeeApp.Models
{
public class ErrorViewModel
{
public string? RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
}
}

View File

@@ -0,0 +1,31 @@
using ComputerStoreEmployeeApp;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllersWithViews();
var app = builder.Build();
APIClient.Connect(builder.Configuration);
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();

View File

@@ -0,0 +1,28 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:7223",
"sslPort": 44339
}
},
"profiles": {
"ComputerStoreEmployeeApp": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "https://localhost:7194;http://localhost:5117",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

View File

@@ -0,0 +1,21 @@
@{
ViewData["Title"] = "Add a component";
}
<div class="text-center">
<h2 class="display-4">Add a component</h2>
</div>
<form method="post">
<div class="flex-container" style="flex-direction: row; justify-content: space-between; display: flex; height: 100vh;">
<div class="flex-containerB1" style="flex-direction: column; flex: 4; gap: 20px; display: flex; align-items: center; justify-content: center;">
<div class="componentname" style="text-align: left; font-size: 15px;">Name:</div>
<input type="text" id="componentname" name="componentname" />
<div class="componentprice" style="text-align: left; font-size: 15px;">Price:</div>
<input type="text" id="componentprice" name="componentprice" />
<input type="submit" id="componentbtn" value="ADD" class="btn btn-primary" />
</div>
</div>
@if (!string.IsNullOrEmpty(ViewBag.Message))
{
<script>alert("@ViewBag.Message");</script>
}
</form>

View File

@@ -0,0 +1,38 @@
@using ComputerStoreContracts.ViewModels
@model List<ComponentViewModel>
@{
ViewData["Title"] = "Storage";
}
<div class="text-center">
<h1 class="display-4">Storage</h1>
</div>
<div class="text-center">
@{
<table class="table">
<thead>
<tr>
<th>
Name
</th>
<th>
Price
</th>
</tr>
</thead>
<tbody>
@foreach (var item in Model)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.Price)
</td>
</tr>
}
</tbody>
</table>
}
</div>

View File

@@ -0,0 +1,18 @@
@{
ViewData["Title"] = "Delete a component";
}
<div class="text-center">
<h2 class="display-4">Delete a component</h2>
</div>
<form method="post">
<div class="flex-container" style="flex-direction: row; justify-content: space-between; display: flex; height: 100vh;">
<div class="flex-containerB1" style="flex-direction: column; flex: 4; gap: 20px; display: flex; align-items: center; justify-content: center;">
<select id="component" name="component" class="form-control" asp-items="@(new SelectList(@ViewBag.Components,"ID","Name"))"></select>
<input type="submit" id="componentbtn" value="DELETE" class="btn btn-primary" />
</div>
</div>
@if (!string.IsNullOrEmpty(ViewBag.Message))
{
<script>alert("@ViewBag.Message");</script>
}
</form>

View File

@@ -0,0 +1,30 @@
@{
ViewData["Title"] = "Components";
}
<div class="text-center">
<div class="flex-container" style="flex-direction: row; justify-content: center; display: flex; height: 100vh;">
<div class="flex-containerA1" style="flex-direction: column; align-items: center; display: flex; gap: 35px">
<h1>What do you want to do with components?</h1>
<div class="flex-containerB1" style="display: flex; align-items: center; margin-top: 120px;">
<form method="get" asp-controller="Home" asp-action="ComponentAdd">
<input type="submit" id="compadd" value="ADD" class="btn btn-primary" style="font-size: 20pt; width: 130px;" />
</form>
</div>
<div class="flex-containerB2" style="display: flex; align-items: center;">
<form method="get" asp-controller="Home" asp-action="ComponentUpdate">
<input type="submit" id="compupdate" value="UPDATE" class="btn btn-primary" style="font-size: 20pt; width: 130px;" />
</form>
</div>
<div class="flex-containerB3" style="display: flex; align-items: center;">
<form method="get" asp-controller="Home" asp-action="ComponentDelete">
<input type="submit" id="compdel" value="DELETE" class="btn btn-primary" style="font-size: 20pt; width: 130px;" />
</form>
</div>
<div class="flex-containerB3" style="display: flex; align-items: center;">
<form method="get" asp-controller="Home" asp-action="ComponentCheck">
<input type="submit" id="compcheck" value="STORAGE" class="btn btn-primary" style="font-size: 20pt; width: 130px;" />
</form>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,22 @@
@{
ViewData["Title"] = "Update a component";
}
<div class="text-center">
<h2 class="display-4">Update a component</h2>
</div>
<form method="post">
<div class="flex-container" style="flex-direction: row; justify-content: space-between; display: flex; height: 100vh;">
<div class="flex-containerB1" style="flex-direction: column; flex: 4; gap: 20px; display: flex; align-items: center; justify-content: center;">
<select id="component" name="component" class="form-control" asp-items="@(new SelectList(@ViewBag.Components,"ID","Name"))"></select>
<div class="componentname" style="text-align: left; font-size: 15px;">Name:</div>
<input type="text" id="componentname" name="componentname" />
<div class="componentprice" style="text-align: left; font-size: 15px;">Price:</div>
<input type="text" id="componentprice" name="componentprice" />
<input type="submit" id="componentbtn" value="CHANGE" class="btn btn-primary" />
</div>
</div>
@if (!string.IsNullOrEmpty(ViewBag.Message))
{
<script>alert("@ViewBag.Message");</script>
}
</form>

View File

@@ -0,0 +1,30 @@
@{
ViewData["Title"] = "Enter";
}
<div class="text-center">
<h2 class="display-4">Sign in</h2>
</div>
<form method="post">
<div class="row">
<div class="col-4">Login:</div>
<div class="col-8"><input type="text" name="login" /></div>
</div>
<div class="row">
<div class="col-4">Password:</div>
<div class="col-8"><input type="password" name="password" /></div>
</div>
<div class="row">
<div class="col-8"></div> <div class="col-8"><input type="submit" id="signin" value="Sign in" class="btn btn-primary" /><input type="submit" id="register" value="Register"/></div>
</div>
@if (!string.IsNullOrEmpty(ViewBag.Message))
{
<script>alert("@ViewBag.Message");</script>
}
</form>
<script>
$('#register').on('click', function (evt) {
evt.preventDefault();
document.location.href='@Url.Action("Register","Home")';
});
</script>

View File

@@ -0,0 +1,8 @@
@{
ViewData["Title"] = "Home page";
}
<div class="text-center">
<h1 class="display-4">ComputerStore"Ты же программист"</h1>
<p>This app was created for employees.</p>
</div>

View File

@@ -0,0 +1,130 @@
@using ComputerStoreDataModels.Models
@using ComputerStoreContracts.ViewModels
@model List<RequestComponentViewModel>
@{
ViewData["Title"] = "Add a PC";
}
<div class="text-center">
<h2 class="display-4">Add a PC</h2>
</div>
<form method="post">
<div class="flex-container" style="flex-direction: row; justify-content: space-between; display: flex; height: 100vh;">
<div class="flex-containerB1" style="flex-direction: column; flex: 4; gap: 20px; display: flex; align-items: center; justify-content: center;">
<h1>Component:</h1>
<select id="component" name="component" class="form-control" asp-items="@(new SelectList(@ViewBag.Components,"ID","Name"))"></select>
<div class="componentquantity" style="text-align: left; font-size: 15px;">Quantity:</div>
<input type="text" id="componentquantity" name="componentquantity" />
<input type="button" id="componentbtn" value="ADD" class="btn btn-primary" />
</div>
<div class="flex-containerB2" style="flex-direction: column; flex: 4; gap: 20px; display: flex; align-items: center; justify-content: center;">
<table class="table">
<thead>
<tr>
<th>
Name
</th>
<th>
Count
</th>
</tr>
</thead>
<tbody>
@foreach ((IComponentModel,int) item in ViewBag.PCComponents.Values)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.Item1.Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.Item2)
</td>
</tr>
}
</tbody>
</table>
</div>
<div class="flex-containerB3" style="flex-direction: column; flex: 4; gap: 20px; display: flex; align-items: center; justify-content: center;">
<h1>PC:</h1>
<div class="pcname" style="text-align: left; font-size: 15px;">Name:</div>
<input type="text" id="pcname" name="pcname" />
<div class="pcprice" style="text-align: left; font-size: 15px;">Price:</div>
<input type="text" id="pcprice" name="pcprice" readonly />
<input type="submit" id="pcbtn" value="ADD" class="btn btn-primary" />
</div>
</div>
<div class="partialView" id="partialView">
<select id="request" name="request" class="form-control" asp-items="@(new SelectList(@ViewBag.Requests,"ID","ID"))"></select>
<table class="table">
<thead>
<tr>
<th>
Component
</th>
<th>
Count
</th>
</tr>
</thead>
<tbody>
@if (Model != null)
{
foreach (var item in Model)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.ComponentName)
</td>
<td>
@Html.DisplayFor(modelItem => item.ComponentCount)
</td>
</tr>
}
}
</tbody>
</table>
</div>
@if (!string.IsNullOrEmpty(ViewBag.Message))
{
<script>alert("@ViewBag.Message");</script>
}
</form>
<script>
window.onsubmit = function () {
localStorage.clear();
}
window.onload = function () {
$('#pcprice').val(localStorage.getItem("price"));
$('#request').val(@ViewBag.ID);
}
$('#request').on('change', function () {
window.location.href = '/Home/PCAdd?request=' + $('#request').val();
});
$('#componentbtn').on("click", function () {
var count = $('#componentquantity').val();
var id = $('#component').val();
$.when(ajax1(id, count)).done(function (a1) {
localStorage.setItem("price", $('#pcprice').val());
window.location.href = '/Home/PCAdd?request=' + $('#request').val();
})
});
function ajax1(id, count) {
return $.ajax({
method: "POST",
url: "/Home/PCComponents",
data: { id: id, componentquantity: count },
success: function (result) {
$('#pcprice').val(result);
}
});
}
</script>

View File

@@ -0,0 +1,60 @@
@using ComputerStoreContracts.ViewModels
@model List<PCViewModel>
@{
ViewData["Title"] = "Storage";
}
<div class="text-center">
<h1 class="display-4">Storage</h1>
</div>
<div class="text-center">
@{
<table class="table">
<thead>
<tr>
<th>
Name
</th>
<th>
Price
</th>
<th>
Employee username
</th>
<th>
Components
</th>
</tr>
</thead>
<tbody>
@foreach (var item in Model)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.Price)
</td>
<td>
@Html.DisplayFor(modelItem => item.EmployeeUsername)
</td>
<td>
<table>
@foreach (var component in item.PCComponents)
{
<tr>
<td>@component.Value.Component.Name</td>
<td></td>
<td>@component.Value.Quantity</td>
</tr>
}
</table>
</td>
</tr>
}
</tbody>
</table>
}
</div>

View File

@@ -0,0 +1,18 @@
@{
ViewData["Title"] = "Delete a product";
}
<div class="text-center">
<h2 class="display-4">Delete a product</h2>
</div>
<form method="post">
<div class="flex-container" style="flex-direction: row; justify-content: space-between; display: flex; height: 100vh;">
<div class="flex-containerB1" style="flex-direction: column; flex: 4; gap: 20px; display: flex; align-items: center; justify-content: center;">
<select id="pc" name="pc" class="form-control" asp-items="@(new SelectList(@ViewBag.PCs,"ID","Name"))"></select>
<input type="submit" id="pcbtn" value="DELETE" class="btn btn-primary" />
</div>
</div>
@if (!string.IsNullOrEmpty(ViewBag.Message))
{
<script>alert("@ViewBag.Message");</script>
}
</form>

View File

@@ -0,0 +1,32 @@
@{
ViewData["Title"] = "PCs";
}
<div class="text-center">
<div class="flex-container" style="flex-direction: row; justify-content: center; display: flex; height: 100vh;">
<div class="flex-containerA1" style="flex-direction: column; align-items: center; display: flex; gap: 35px">
<h1>What do you want to do with pcs?</h1>
<div class="flex-containerB1" style="display: flex; align-items: center; margin-top: 120px;">
<form method="get" asp-controller="Home" asp-action="PCAdd">
<input type="submit" id="pcadd" value="ADD" class="btn btn-primary" style="font-size: 20pt; width: 130px;" />
</form>
</div>
<div class="flex-containerB2" style="display: flex; align-items: center;">
<form method="get" asp-controller="Home" asp-action="PCUpdate" asp-route-id="null">
<input type="submit" id="pcupdate" value="UPDATE" class="btn btn-primary" style="font-size: 20pt; width: 130px;" />
</form>
</div>
<div class="flex-containerB3" style="display: flex; align-items: center;">
<form method="get" asp-controller="Home" asp-action="PCDelete">
<input type="submit" id="pcdel" value="DELETE" class="btn btn-primary" style="font-size: 20pt; width: 130px;" />
</form>
</div>
<div class="flex-containerB3" style="display: flex; align-items: center;">
<form method="get" asp-controller="Home" asp-action="PCCheck">
<input type="submit" id="pccheck" value="STORAGE" class="btn btn-primary" style="font-size: 20pt; width: 130px;" />
</form>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,96 @@
@using ComputerStoreDataModels.Models;
@model Dictionary<int,(IComponentModel,int)>
@{
ViewData["Title"] = "Update a PC";
}
<div class="text-center">
<h2 class="display-4">Update a PC</h2>
</div>
<form method="post">
<div class="flex-container" style="flex-direction: row; justify-content: space-between; display: flex; height: 100vh;">
<div class="flex-containerB1" style="flex-direction: column; flex: 4; gap: 20px; display: flex; align-items: center; justify-content: center;">
<h1>Component:</h1>
<select id="component" name="component" class="form-control" asp-items="@(new SelectList(@ViewBag.Components,"ID","Name"))"></select>
<div class="componentquantity" style="text-align: left; font-size: 15px;">Quantity:</div>
<input type="text" id="componentquantity" name="componentquantity" />
<input type="button" id="componentbtn" value="MODIFY" class="btn btn-primary" />
</div>
<div class="flex-containerB2" style="flex-direction: column; flex: 4; gap: 20px; display: flex; align-items: center; justify-content: center;">
<table class="table">
<thead>
<tr>
<th>
Name
</th>
<th>
Count
</th>
</tr>
</thead>
<tbody>
@foreach (var item in Model)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.Value.Item1.Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.Value.Item2)
</td>
</tr>
}
</tbody>
</table>
</div>
<div class="flex-containerB3" style="flex-direction: column; flex: 4; gap: 20px; display: flex; align-items: center; justify-content: center;">
<h1>PC:</h1>
<select id="pc" name="pc" class="form-control" asp-items="@(new SelectList(@ViewBag.PCs,"ID","Name"))"></select>
<div class="pcname" style="text-align: left; font-size: 15px;">Name:</div>
<input type="text" id="pcname" name="pcname" />
<div class="pcprice" style="text-align: left; font-size: 15px;">Price:</div>
<input type="text" id="pcprice" name="pcprice" readonly />
<input type="submit" id="pcbtn" value="UPDATE" class="btn btn-primary" />
</div>
</div>
@if (!string.IsNullOrEmpty(ViewBag.Message))
{
<script>alert("@ViewBag.Message");</script>
}
</form>
<script>
window.onload = function () {
$('#pc').val(@ViewBag.ID);
$('#pcprice').val(@ViewBag.Price);
}
$('#pc').on('change', function () {
var pcid = $('#pc').val();
window.location.href = '/Home/PCUpdate/' + pcid + '?selectChange=' + true;
});
$('#componentbtn').on("click", function () {
var count = $('#componentquantity').val();
var id = $('#component').val();
$.when(ajax1(id, count)).done(function (a1) {
localStorage.setItem("price", $('#pcprice').val());
var pcid = $('#pc').val();
window.location.href = '/Home/PCUpdate/' + pcid
})
});
function ajax1(id, count) {
return $.ajax({
method: "POST",
url: "/Home/PCComponents",
data: { id: id, componentquantity: count },
success: function (result) {
$('#pcprice').val(result);
}
});
}
</script>

View File

@@ -0,0 +1,6 @@
@{
ViewData["Title"] = "Privacy Policy";
}
<h1>@ViewData["Title"]</h1>
<p>Use this page to detail your site's privacy policy.</p>

View File

@@ -0,0 +1,91 @@
@using ComputerStoreDataModels.Models;
@model Dictionary<int, (IComponentModel, int)>
@{
ViewData["Title"] = "Add a product";
}
<div class="text-center">
<h2 class="display-4">Add a product</h2>
</div>
<form method="post">
<div class="flex-container" style="flex-direction: row; justify-content: space-between; display: flex; height: 100vh;">
<div class="flex-containerB1" style="flex-direction: column; flex: 4; gap: 20px; display: flex; align-items: center; justify-content: center;">
<h1>Component:</h1>
<select id="component" name="component" class="form-control" asp-items="@(new SelectList(@ViewBag.Components,"ID","Name"))"></select>
<div class="productprice" style="text-align: left; font-size: 15px;">Quantity:</div>
<input type="text" id="componentquantity" name="componentquantity" />
<input type="button" id="componentbtn" value="ADD" class="btn btn-primary" />
</div>
<div class="flex-containerB2" style="flex-direction: column; flex: 4; gap: 20px; display: flex; align-items: center; justify-content: center;">
<table class="table">
<thead>
<tr>
<th>
Name
</th>
<th>
Count
</th>
</tr>
</thead>
<tbody>
@foreach (var item in Model)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.Value.Item1.Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.Value.Item2)
</td>
</tr>
}
</tbody>
</table>
</div>
<div class="flex-containerB3" style="flex-direction: column; flex: 4; gap: 20px; display: flex; align-items: center; justify-content: center;">
<h1>Product:</h1>
<div class="productname" style="text-align: left; font-size: 15px;">Name:</div>
<input type="text" id="productname" name="productname" />
<div class="productprice" style="text-align: left; font-size: 15px;">Price:</div>
<input type="text" id="productprice" name="productprice" readonly />
<input type="submit" id="productbtn" value="ADD" class="btn btn-primary" />
</div>
</div>
@if (!string.IsNullOrEmpty(ViewBag.Message))
{
<script>alert("@ViewBag.Message");</script>
}
</form>
<script>
window.onsubmit = function(){
localStorage.clear();
}
window.onload = function(){
$('#productprice').val(localStorage.getItem("price"));
}
$('#componentbtn').on("click", function(){
var count = $('#componentquantity').val();
var id = $('#component').val();
$.when(ajax1(id, count)).done(function (a1) {
localStorage.setItem("price", $('#productprice').val());
window.location.href = '/Home/ProductAdd'
})
});
function ajax1(id, count) {
return $.ajax({
method: "POST",
url: "/Home/ProductComponents",
data: { id: id, componentquantity: count },
success: function (result) {
$('#productprice').val(result);
}
});
}
</script>

View File

@@ -0,0 +1,60 @@
@using ComputerStoreContracts.ViewModels
@model List<ProductViewModel>
@{
ViewData["Title"] = "Storage";
}
<div class="text-center">
<h1 class="display-4">Storage</h1>
</div>
<div class="text-center">
@{
<table class="table">
<thead>
<tr>
<th>
Name
</th>
<th>
Price
</th>
<th>
Employee username
</th>
<th>
Components
</th>
</tr>
</thead>
<tbody>
@foreach (var item in Model)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.Price)
</td>
<td>
@Html.DisplayFor(modelItem => item.EmployeeUsername)
</td>
<td>
<table>
@foreach (var component in item.ProductComponents)
{
<tr>
<td>@component.Value.Component.Name</td>
<td></td>
<td>@component.Value.Quantity</td>
</tr>
}
</table>
</td>
</tr>
}
</tbody>
</table>
}
</div>

View File

@@ -0,0 +1,18 @@
@{
ViewData["Title"] = "Delete a product";
}
<div class="text-center">
<h2 class="display-4">Delete a product</h2>
</div>
<form method="post">
<div class="flex-container" style="flex-direction: row; justify-content: space-between; display: flex; height: 100vh;">
<div class="flex-containerB1" style="flex-direction: column; flex: 4; gap: 20px; display: flex; align-items: center; justify-content: center;">
<select id="product" name="product" class="form-control" asp-items="@(new SelectList(@ViewBag.Products,"ID","Name"))"></select>
<input type="submit" id="productbtn" value="DELETE" class="btn btn-primary" />
</div>
</div>
@if (!string.IsNullOrEmpty(ViewBag.Message))
{
<script>alert("@ViewBag.Message");</script>
}
</form>

View File

@@ -0,0 +1,32 @@
@{
ViewData["Title"] = "Products";
}
<div class="text-center">
<div class="flex-container" style="flex-direction: row; justify-content: center; display: flex; height: 100vh;">
<div class="flex-containerA1" style="flex-direction: column; align-items: center; display: flex; gap: 35px">
<h1>What do you want to do with products?</h1>
<div class="flex-containerB1" style="display: flex; align-items: center; margin-top: 120px;">
<form method="get" asp-controller="Home" asp-action="ProductAdd">
<input type="submit" id="productadd" value="ADD" class="btn btn-primary" style="font-size: 20pt; width: 130px;" />
</form>
</div>
<div class="flex-containerB2" style="display: flex; align-items: center;">
<form method="get" asp-controller="Home" asp-action="ProductUpdate" asp-route-id="null">
<input type="submit" id="productupdate" value="UPDATE" class="btn btn-primary" style="font-size: 20pt; width: 130px;" />
</form>
</div>
<div class="flex-containerB3" style="display: flex; align-items: center;">
<form method="get" asp-controller="Home" asp-action="ProductDelete">
<input type="submit" id="productdel" value="DELETE" class="btn btn-primary" style="font-size: 20pt; width: 130px;" />
</form>
</div>
<div class="flex-containerB3" style="display: flex; align-items: center;">
<form method="get" asp-controller="Home" asp-action="ProductCheck">
<input type="submit" id="productcheck" value="STORAGE" class="btn btn-primary" style="font-size: 20pt; width: 130px;" />
</form>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,96 @@
@using ComputerStoreDataModels.Models;
@model Dictionary<int,(IComponentModel,int)>
@{
ViewData["Title"] = "Update a product";
}
<div class="text-center">
<h2 class="display-4">Update a product</h2>
</div>
<form method="post">
<div class="flex-container" style="flex-direction: row; justify-content: space-between; display: flex; height: 100vh;">
<div class="flex-containerB1" style="flex-direction: column; flex: 4; gap: 20px; display: flex; align-items: center; justify-content: center;">
<h1>Component:</h1>
<select id="component" name="component" class="form-control" asp-items="@(new SelectList(@ViewBag.Components,"ID","Name"))"></select>
<div class="componentquantity" style="text-align: left; font-size: 15px;">Quantity:</div>
<input type="text" id="componentquantity" name="componentquantity" />
<input type="button" id="componentbtn" value="MODIFY" class="btn btn-primary" />
</div>
<div class="flex-containerB2" style="flex-direction: column; flex: 4; gap: 20px; display: flex; align-items: center; justify-content: center;">
<table class="table">
<thead>
<tr>
<th>
Name
</th>
<th>
Count
</th>
</tr>
</thead>
<tbody>
@foreach (var item in Model)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.Value.Item1.Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.Value.Item2)
</td>
</tr>
}
</tbody>
</table>
</div>
<div class="flex-containerB3" style="flex-direction: column; flex: 4; gap: 20px; display: flex; align-items: center; justify-content: center;">
<h1>Product:</h1>
<select id="product" name="product" class="form-control" asp-items="@(new SelectList(@ViewBag.Products,"ID","Name"))"></select>
<div class="productname" style="text-align: left; font-size: 15px;">Name:</div>
<input type="text" id="productname" name="productname" />
<div class="productprice" style="text-align: left; font-size: 15px;">Price:</div>
<input type="text" id="productprice" name="productprice" readonly />
<input type="submit" id="productbtn" value="UPDATE" class="btn btn-primary" />
</div>
</div>
@if (!string.IsNullOrEmpty(ViewBag.Message))
{
<script>alert("@ViewBag.Message");</script>
}
</form>
<script>
window.onload = function () {
$('#product').val(@ViewBag.ID);
$('#productprice').val(@ViewBag.Price);
}
$('#product').on('change',function() {
var productid = $('#product').val();
window.location.href = '/Home/ProductUpdate/' + productid + '?selectChange=' + true;
});
$('#componentbtn').on("click", function () {
var count = $('#componentquantity').val();
var id = $('#component').val();
$.when(ajax1(id, count)).done(function (a1) {
localStorage.setItem("price", $('#productprice').val());
var productid = $('#product').val();
window.location.href = '/Home/ProductUpdate/' + productid
})
});
function ajax1(id, count) {
return $.ajax({
method: "POST",
url: "/Home/ProductComponents",
data: { id: id, componentquantity: count },
success: function (result) {
$('#productprice').val(result);
}
});
}
</script>

View File

@@ -0,0 +1,39 @@
@{
ViewData["Title"] = "Register";
}
<div class="text-center">
<h2 class="display-4">Register</h2>
</div>
<form method="post">
<div class="flex-container" style="flex-direction: row; justify-content: center; display: flex; height: 100vh; gap: 80px">
<div class="flex-containerC1" style="flex-direction:column; justify-content: center; display:flex;">
<p>USERNAME*</p>
<input type="text" id="username" name="username" />
<p>PASSWORD*</p>
<input type="password" id="password" name="password" />
</div>
<div class="flex-containerC2" style="flex-direction:column; justify-content: center; display:flex; gap: 10px">
<p>FIRST NAME*</p>
<input type="text" id="firstname" name="firstname" />
<p>LAST NAME*</p>
<input type="text" id="lastname" name="lastname" />
<p>MIDDLE NAME*</p>
<input type="text" id="middlename" name="middlename" />
<aside style="margin-top: 10px;"></aside>
<input type="submit" value="Register" class="btn btn-primary" />
<input id="sign" type="submit" value="Sign In"/>
</div>
</div>
@if (!string.IsNullOrEmpty(ViewBag.Message))
{
<script>alert("@ViewBag.Message");</script>
}
</form>
<script>
$('#sign').on('click', function (evt) {
evt.preventDefault();
document.location.href='@Url.Action("Enter","Home")';
});
</script>

View File

@@ -0,0 +1,126 @@
@using ComputerStoreDataModels.Models;
@using ComputerStoreContracts.ViewModels;
@model Dictionary<int, (IComponentModel, int)>
@{
ViewData["Title"] = "Find consignment by components";
}
<div class="text-center">
<h2 class="display-4">Enter components</h2>
</div>
<div>
@if(ViewBag.Components != null)
{
<div class="flex-container" style="flex-direction: row; justify-content: space-between; display: flex; height: 100vh; gap: 20px; align-items: center;">
<div class="flex-containerB1" style="flex-direction: column; flex: 4; gap: 20px; display: flex; align-items: center; justify-content: center;">
<h1>Component:</h1>
<select id="component" name="component" class="form-control" asp-items="@(new SelectList(@ViewBag.Components,"ID","Name"))"></select>
<input type="button" id="componentbtn" value="ADD" class="btn btn-primary" />
</div>
<div class="flex-containerB2" style="flex-direction: column; flex: 4; gap: 20px; display: flex; align-items: center; justify-content: center;">
<table class="table">
<thead>
<tr>
<th>
Name
</th>
</tr>
</thead>
<tbody>
@foreach (var item in Model)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.Value.Item1.Name)
</td>
</tr>
}
</tbody>
</table>
</div>
<input type="button" id="findbtn" value="FIND" class="btn btn-primary" />
</div>
}
@if(ViewBag.Consignments != null)
{
<div class="flex-containerC1" style="flex-direction: row; flex: 4; gap: 20px; display: flex; align-items: center; justify-content: center;">
<table class="table">
<thead>
<tr>
<th>
ConsignmentID
</th>
<th>
Products
</th>
</tr>
</thead>
<tbody>
@foreach (ReportConsignmentsViewModel item in ViewBag.Consignments)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.ID)
</td>
<td>
<table>
@foreach (var product in item.Products)
{
<tr>
<td>@product.product</td>
</tr>
}
</table>
</td>
</tr>
}
</tbody>
</table>
<div class="flex-containerB2" style="flex-direction: column; flex: 4; gap: 20px; display: flex; align-items: center; justify-content: center;">
<form method="post" action="@Url.Action("SaveWord","Report")">
<input type="submit" id="wordbtn" value="Save word" class="btn btn-primary" style="font-size: 20pt; width: auto;" />
</form>
</div>
<form method="post" action="@Url.Action("SaveExcel","Report")">
<input type="submit" id="excelbtn" value="Save excel" class="btn btn-primary" style="font-size: 20pt; width: auto;" />
</form>
</div>
}
@if (!string.IsNullOrEmpty(ViewBag.Message))
{
<script>alert("@ViewBag.Message");</script>
}
</div>
<script>
$('#componentbtn').on("click", function () {
var id = $('#component').val();
$.when(ajax1(id)).done(function (a1) {
window.location.href = '/Report/ConsignmentsReport'
})
});
$('#findbtn').on("click", function () {
window.location.href = '/Report/ConsignmentsReportResult'
});
function ajax1(id) {
return $.ajax({
method: "POST",
url: "/Report/ConsignmentComponents",
data: { id: id}
});
}
</script>

View File

@@ -0,0 +1,166 @@
@using ComputerStoreDataModels.Models;
@using ComputerStoreContracts.ViewModels;
@{
ViewData["Title"] = "Find products and pcs by date";
}
<div>
<div class="flex-container" style="flex-direction: row; justify-content: space-between; display: flex; gap: 20px; align-items: flex-start;">
<form method="get" action="@Url.Action("PCsProductsReportResult","Report")">
<input type="date" id="fromdate" name="fromdate">
<input type="date" id="todate" name="todate">
<input type="submit" id="findbtn" value="SEARCH" class="btn btn-primary" />
</form>
</div>
@if (ViewBag.Search != null)
{
<div class="flex-containerC1" style="flex-direction: row; flex: 4; gap: 20px; display: flex; align-items: center; justify-content: center;">
<table class="table">
<thead>
<tr>
<th>
PC's name
</th>
<th>
Employee's username
</th>
<th>
Total
</th>
<th>
Components
</th>
</tr>
</thead>
<tbody>
@foreach (ReportPCByDateViewModel item in ViewBag.PCs)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.PCName)
</td>
<td>
@Html.DisplayFor(modelItem => item.EmployeeUsername)
</td>
<td>
@Html.DisplayFor(modelItem => item.Price)
</td>
<td>
<table>
@foreach (var component in item.Components)
{
<tr>
<td>@component.Component</td>
<td></td>
<td>@component.count</td>
</tr>
}
</table>
</td>
</tr>
}
</tbody>
</table>
<table class="table">
<thead>
<tr>
<th>
Product's name
</th>
<th>
Employee's username
</th>
<th>
Total
</th>
<th>
Components
</th>
</tr>
</thead>
<tbody>
@foreach (ReportProductByDateViewModel item in ViewBag.Products)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.ProductName)
</td>
<td>
@Html.DisplayFor(modelItem => item.EmployeeUsername)
</td>
<td>
@Html.DisplayFor(modelItem => item.Price)
</td>
<td>
<table>
@foreach (var component in item.Components)
{
<tr>
<td>@component.Component</td>
<td></td>
<td>@component.count</td>
</tr>
}
</table>
</td>
</tr>
}
</tbody>
</table>
<div class="flex-containerB2" style="flex-direction: column; flex: 4; gap: 20px; display: flex; align-items: center; justify-content: center;">
<input type="text" id="email" name="email" />
<input type="submit" id="sendbtn" value="Send email" class="btn btn-primary" style="font-size: 20pt; width: auto;" />
</div>
</div>
}
@if (!string.IsNullOrEmpty(ViewBag.Message))
{
<script>alert("@ViewBag.Message");</script>
}
</div>
<script>
window.onsubmit = function () {
localStorage.setItem("to", $('#todate').val());
localStorage.setItem("from", $('#fromdate').val());
}
window.onload = function () {
$('#fromdate').val(localStorage.getItem("from"));
$('#todate').val(localStorage.getItem("to"));
}
$('#sendbtn').on("click", function () {
var datef = $('#fromdate').val();
var datet = $('#todate').val();
var email = $('#email').val();
$.when(ajax1(datet, datef, email)).done(function () {
localStorage.clear();
window.location.href = '/Report/ReportMenu'
})
});
function ajax1(datef, datet, email) {
return $.ajax({
method: "POST",
url: "/Report/SendEmail",
data: { email: email, datefrom: datet, dateto: datef }
});
}
</script>

View File

@@ -0,0 +1,20 @@
@{
ViewData["Title"] = "Reports";
}
<div class="text-center">
<div class="flex-container" style="flex-direction: row; justify-content: center; display: flex; height: 100vh;">
<div class="flex-containerA1" style="flex-direction: column; align-items: center; display: flex; gap: 35px">
<h1>Which kind of report do you want to receive?</h1>
<div class="flex-containerB1" style="display: flex; align-items: center; margin-top: 120px;">
<form method="get" asp-controller="Report" asp-action="ConsignmentsReport">
<input type="submit" id="consreport" value="Consignments report by components" class="btn btn-primary" style="font-size: 20pt; width: auto;" />
</form>
</div>
<div class="flex-containerB2" style="display: flex; align-items: center;">
<form method="get" asp-controller="Report" asp-action="PCsProductsReport">
<input type="submit" id="datereport" value="PCs and Products by date" class="btn btn-primary" style="font-size: 20pt; width: auto;" />
</form>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,25 @@
@model ErrorViewModel
@{
ViewData["Title"] = "Error";
}
<h1 class="text-danger">Error.</h1>
<h2 class="text-danger">An error occurred while processing your request.</h2>
@if (Model.ShowRequestId)
{
<p>
<strong>Request ID:</strong> <code>@Model.RequestId</code>
</p>
}
<h3>Development Mode</h3>
<p>
Swapping to <strong>Development</strong> environment will display more detailed information about the error that occurred.
</p>
<p>
<strong>The Development environment shouldn't be enabled for deployed applications.</strong>
It can result in displaying sensitive information from exceptions to end users.
For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>
and restarting the app.
</p>

View File

@@ -0,0 +1,32 @@
@using ComputerStoreContracts.ViewModels
@model List<RequestComponentViewModel>
<select id="request" name="request" class="form-control" asp-items="@(new SelectList(@ViewBag.Requests,"ID","ID"))"></select>
<table class="table">
<thead>
<tr>
<th>
Component
</th>
<th>
Count
</th>
</tr>
</thead>
<tbody>
@if(Model != null)
{
foreach (var item in Model)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.ComponentName)
</td>
<td>
@Html.DisplayFor(modelItem => item.ComponentCount)
</td>
</tr>
}
}
</tbody>
</table>

View File

@@ -0,0 +1,64 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>@ViewData["Title"] - EmployeeApp</title>
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
<link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
<link rel="stylesheet" href="~/ComputerStoreEmployeeApp.styles.css" asp-append-version="true" />
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
</head>
<body>
@if(ViewBag.ShowTopBar == null)
{
<header>
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
<div class="container-fluid">
<a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">EmployeeApp</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target=".navbar-collapse" aria-controls="navbarSupportedContent"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
<ul class="navbar-nav flex-grow-1">
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Menu</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="ComponentMenu">Components</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="ProductMenu">Products</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="PCMenu">PCs</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Report" asp-action="ReportMenu">Reports</a>
</li>
</ul>
</div>
</div>
</nav>
</header>
}
else
{
}
<div class="container">
<main role="main" class="pb-3">
@RenderBody()
</main>
</div>
<footer class="border-top footer text-muted">
<div class="container">
&copy; 2023 - ComputerStoreEmployeeApp
</div>
</footer>
<script src="~/js/site.js" asp-append-version="true"></script> @await RenderSectionAsync("Scripts", required: false)
</body>
</html>

View File

@@ -0,0 +1,48 @@
/* Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification
for details on configuring this project to bundle and minify static web assets. */
a.navbar-brand {
white-space: normal;
text-align: center;
word-break: break-all;
}
a {
color: #0077cc;
}
.btn-primary {
color: #fff;
background-color: #1b6ec2;
border-color: #1861ac;
}
.nav-pills .nav-link.active, .nav-pills .show > .nav-link {
color: #fff;
background-color: #1b6ec2;
border-color: #1861ac;
}
.border-top {
border-top: 1px solid #e5e5e5;
}
.border-bottom {
border-bottom: 1px solid #e5e5e5;
}
.box-shadow {
box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05);
}
button.accept-policy {
font-size: 1rem;
line-height: inherit;
}
.footer {
position: absolute;
bottom: 0;
width: 100%;
white-space: nowrap;
line-height: 60px;
}

View File

@@ -0,0 +1,2 @@
<script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script>
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>

View File

@@ -0,0 +1,3 @@
@using ComputerStoreEmployeeApp
@using ComputerStoreEmployeeApp.Models
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

View File

@@ -0,0 +1,3 @@
@{
Layout = "_Layout";
}

View File

@@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}

View File

@@ -0,0 +1,10 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"IPAddress": "http://localhost:5112/"
}

View File

@@ -0,0 +1,18 @@
html {
font-size: 14px;
}
@media (min-width: 768px) {
html {
font-size: 16px;
}
}
html {
position: relative;
min-height: 100%;
}
body {
margin-bottom: 60px;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

@@ -0,0 +1,4 @@
// Please see documentation at https://docs.microsoft.com/aspnet/core/client-side/bundling-and-minification
// for details on configuring this project to bundle and minify static web assets.
// Write your JavaScript code.

View File

@@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2011-2021 Twitter, Inc.
Copyright (c) 2011-2021 The Bootstrap Authors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,427 @@
/*!
* Bootstrap Reboot v5.1.0 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors
* Copyright 2011-2021 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
*/
*,
*::before,
*::after {
box-sizing: border-box;
}
@media (prefers-reduced-motion: no-preference) {
:root {
scroll-behavior: smooth;
}
}
body {
margin: 0;
font-family: var(--bs-body-font-family);
font-size: var(--bs-body-font-size);
font-weight: var(--bs-body-font-weight);
line-height: var(--bs-body-line-height);
color: var(--bs-body-color);
text-align: var(--bs-body-text-align);
background-color: var(--bs-body-bg);
-webkit-text-size-adjust: 100%;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
hr {
margin: 1rem 0;
color: inherit;
background-color: currentColor;
border: 0;
opacity: 0.25;
}
hr:not([size]) {
height: 1px;
}
h6, h5, h4, h3, h2, h1 {
margin-top: 0;
margin-bottom: 0.5rem;
font-weight: 500;
line-height: 1.2;
}
h1 {
font-size: calc(1.375rem + 1.5vw);
}
@media (min-width: 1200px) {
h1 {
font-size: 2.5rem;
}
}
h2 {
font-size: calc(1.325rem + 0.9vw);
}
@media (min-width: 1200px) {
h2 {
font-size: 2rem;
}
}
h3 {
font-size: calc(1.3rem + 0.6vw);
}
@media (min-width: 1200px) {
h3 {
font-size: 1.75rem;
}
}
h4 {
font-size: calc(1.275rem + 0.3vw);
}
@media (min-width: 1200px) {
h4 {
font-size: 1.5rem;
}
}
h5 {
font-size: 1.25rem;
}
h6 {
font-size: 1rem;
}
p {
margin-top: 0;
margin-bottom: 1rem;
}
abbr[title],
abbr[data-bs-original-title] {
-webkit-text-decoration: underline dotted;
text-decoration: underline dotted;
cursor: help;
-webkit-text-decoration-skip-ink: none;
text-decoration-skip-ink: none;
}
address {
margin-bottom: 1rem;
font-style: normal;
line-height: inherit;
}
ol,
ul {
padding-left: 2rem;
}
ol,
ul,
dl {
margin-top: 0;
margin-bottom: 1rem;
}
ol ol,
ul ul,
ol ul,
ul ol {
margin-bottom: 0;
}
dt {
font-weight: 700;
}
dd {
margin-bottom: 0.5rem;
margin-left: 0;
}
blockquote {
margin: 0 0 1rem;
}
b,
strong {
font-weight: bolder;
}
small {
font-size: 0.875em;
}
mark {
padding: 0.2em;
background-color: #fcf8e3;
}
sub,
sup {
position: relative;
font-size: 0.75em;
line-height: 0;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
a {
color: #0d6efd;
text-decoration: underline;
}
a:hover {
color: #0a58ca;
}
a:not([href]):not([class]), a:not([href]):not([class]):hover {
color: inherit;
text-decoration: none;
}
pre,
code,
kbd,
samp {
font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
font-size: 1em;
direction: ltr /* rtl:ignore */;
unicode-bidi: bidi-override;
}
pre {
display: block;
margin-top: 0;
margin-bottom: 1rem;
overflow: auto;
font-size: 0.875em;
}
pre code {
font-size: inherit;
color: inherit;
word-break: normal;
}
code {
font-size: 0.875em;
color: #d63384;
word-wrap: break-word;
}
a > code {
color: inherit;
}
kbd {
padding: 0.2rem 0.4rem;
font-size: 0.875em;
color: #fff;
background-color: #212529;
border-radius: 0.2rem;
}
kbd kbd {
padding: 0;
font-size: 1em;
font-weight: 700;
}
figure {
margin: 0 0 1rem;
}
img,
svg {
vertical-align: middle;
}
table {
caption-side: bottom;
border-collapse: collapse;
}
caption {
padding-top: 0.5rem;
padding-bottom: 0.5rem;
color: #6c757d;
text-align: left;
}
th {
text-align: inherit;
text-align: -webkit-match-parent;
}
thead,
tbody,
tfoot,
tr,
td,
th {
border-color: inherit;
border-style: solid;
border-width: 0;
}
label {
display: inline-block;
}
button {
border-radius: 0;
}
button:focus:not(:focus-visible) {
outline: 0;
}
input,
button,
select,
optgroup,
textarea {
margin: 0;
font-family: inherit;
font-size: inherit;
line-height: inherit;
}
button,
select {
text-transform: none;
}
[role=button] {
cursor: pointer;
}
select {
word-wrap: normal;
}
select:disabled {
opacity: 1;
}
[list]::-webkit-calendar-picker-indicator {
display: none;
}
button,
[type=button],
[type=reset],
[type=submit] {
-webkit-appearance: button;
}
button:not(:disabled),
[type=button]:not(:disabled),
[type=reset]:not(:disabled),
[type=submit]:not(:disabled) {
cursor: pointer;
}
::-moz-focus-inner {
padding: 0;
border-style: none;
}
textarea {
resize: vertical;
}
fieldset {
min-width: 0;
padding: 0;
margin: 0;
border: 0;
}
legend {
float: left;
width: 100%;
padding: 0;
margin-bottom: 0.5rem;
font-size: calc(1.275rem + 0.3vw);
line-height: inherit;
}
@media (min-width: 1200px) {
legend {
font-size: 1.5rem;
}
}
legend + * {
clear: left;
}
::-webkit-datetime-edit-fields-wrapper,
::-webkit-datetime-edit-text,
::-webkit-datetime-edit-minute,
::-webkit-datetime-edit-hour-field,
::-webkit-datetime-edit-day-field,
::-webkit-datetime-edit-month-field,
::-webkit-datetime-edit-year-field {
padding: 0;
}
::-webkit-inner-spin-button {
height: auto;
}
[type=search] {
outline-offset: -2px;
-webkit-appearance: textfield;
}
/* rtl:raw:
[type="tel"],
[type="url"],
[type="email"],
[type="number"] {
direction: ltr;
}
*/
::-webkit-search-decoration {
-webkit-appearance: none;
}
::-webkit-color-swatch-wrapper {
padding: 0;
}
::file-selector-button {
font: inherit;
}
::-webkit-file-upload-button {
font: inherit;
-webkit-appearance: button;
}
output {
display: inline-block;
}
iframe {
border: 0;
}
summary {
display: list-item;
cursor: pointer;
}
progress {
vertical-align: baseline;
}
[hidden] {
display: none !important;
}
/*# sourceMappingURL=bootstrap-reboot.css.map */

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,8 @@
/*!
* Bootstrap Reboot v5.1.0 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors
* Copyright 2011-2021 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
*/*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;background-color:currentColor;border:0;opacity:.25}hr:not([size]){height:1px}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2}h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){h1{font-size:2.5rem}}h2{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){h2{font-size:2rem}}h3{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){h3{font-size:1.75rem}}h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){h4{font-size:1.5rem}}h5{font-size:1.25rem}h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[data-bs-original-title],abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:.875em}mark{padding:.2em;background-color:#fcf8e3}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#0d6efd;text-decoration:underline}a:hover{color:#0a58ca}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em;direction:ltr;unicode-bidi:bidi-override}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:#d63384;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:.875em;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:1em;font-weight:700}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:#6c757d;text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]::-webkit-calendar-picker-indicator{display:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + .3vw);line-height:inherit}@media (min-width:1200px){legend{font-size:1.5rem}}legend+*{clear:left}::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-text,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:textfield}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::file-selector-button{font:inherit}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none!important}
/*# sourceMappingURL=bootstrap-reboot.min.css.map */

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,424 @@
/*!
* Bootstrap Reboot v5.1.0 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors
* Copyright 2011-2021 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
*/
*,
*::before,
*::after {
box-sizing: border-box;
}
@media (prefers-reduced-motion: no-preference) {
:root {
scroll-behavior: smooth;
}
}
body {
margin: 0;
font-family: var(--bs-body-font-family);
font-size: var(--bs-body-font-size);
font-weight: var(--bs-body-font-weight);
line-height: var(--bs-body-line-height);
color: var(--bs-body-color);
text-align: var(--bs-body-text-align);
background-color: var(--bs-body-bg);
-webkit-text-size-adjust: 100%;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
hr {
margin: 1rem 0;
color: inherit;
background-color: currentColor;
border: 0;
opacity: 0.25;
}
hr:not([size]) {
height: 1px;
}
h6, h5, h4, h3, h2, h1 {
margin-top: 0;
margin-bottom: 0.5rem;
font-weight: 500;
line-height: 1.2;
}
h1 {
font-size: calc(1.375rem + 1.5vw);
}
@media (min-width: 1200px) {
h1 {
font-size: 2.5rem;
}
}
h2 {
font-size: calc(1.325rem + 0.9vw);
}
@media (min-width: 1200px) {
h2 {
font-size: 2rem;
}
}
h3 {
font-size: calc(1.3rem + 0.6vw);
}
@media (min-width: 1200px) {
h3 {
font-size: 1.75rem;
}
}
h4 {
font-size: calc(1.275rem + 0.3vw);
}
@media (min-width: 1200px) {
h4 {
font-size: 1.5rem;
}
}
h5 {
font-size: 1.25rem;
}
h6 {
font-size: 1rem;
}
p {
margin-top: 0;
margin-bottom: 1rem;
}
abbr[title],
abbr[data-bs-original-title] {
-webkit-text-decoration: underline dotted;
text-decoration: underline dotted;
cursor: help;
-webkit-text-decoration-skip-ink: none;
text-decoration-skip-ink: none;
}
address {
margin-bottom: 1rem;
font-style: normal;
line-height: inherit;
}
ol,
ul {
padding-right: 2rem;
}
ol,
ul,
dl {
margin-top: 0;
margin-bottom: 1rem;
}
ol ol,
ul ul,
ol ul,
ul ol {
margin-bottom: 0;
}
dt {
font-weight: 700;
}
dd {
margin-bottom: 0.5rem;
margin-right: 0;
}
blockquote {
margin: 0 0 1rem;
}
b,
strong {
font-weight: bolder;
}
small {
font-size: 0.875em;
}
mark {
padding: 0.2em;
background-color: #fcf8e3;
}
sub,
sup {
position: relative;
font-size: 0.75em;
line-height: 0;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
a {
color: #0d6efd;
text-decoration: underline;
}
a:hover {
color: #0a58ca;
}
a:not([href]):not([class]), a:not([href]):not([class]):hover {
color: inherit;
text-decoration: none;
}
pre,
code,
kbd,
samp {
font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
font-size: 1em;
direction: ltr ;
unicode-bidi: bidi-override;
}
pre {
display: block;
margin-top: 0;
margin-bottom: 1rem;
overflow: auto;
font-size: 0.875em;
}
pre code {
font-size: inherit;
color: inherit;
word-break: normal;
}
code {
font-size: 0.875em;
color: #d63384;
word-wrap: break-word;
}
a > code {
color: inherit;
}
kbd {
padding: 0.2rem 0.4rem;
font-size: 0.875em;
color: #fff;
background-color: #212529;
border-radius: 0.2rem;
}
kbd kbd {
padding: 0;
font-size: 1em;
font-weight: 700;
}
figure {
margin: 0 0 1rem;
}
img,
svg {
vertical-align: middle;
}
table {
caption-side: bottom;
border-collapse: collapse;
}
caption {
padding-top: 0.5rem;
padding-bottom: 0.5rem;
color: #6c757d;
text-align: right;
}
th {
text-align: inherit;
text-align: -webkit-match-parent;
}
thead,
tbody,
tfoot,
tr,
td,
th {
border-color: inherit;
border-style: solid;
border-width: 0;
}
label {
display: inline-block;
}
button {
border-radius: 0;
}
button:focus:not(:focus-visible) {
outline: 0;
}
input,
button,
select,
optgroup,
textarea {
margin: 0;
font-family: inherit;
font-size: inherit;
line-height: inherit;
}
button,
select {
text-transform: none;
}
[role=button] {
cursor: pointer;
}
select {
word-wrap: normal;
}
select:disabled {
opacity: 1;
}
[list]::-webkit-calendar-picker-indicator {
display: none;
}
button,
[type=button],
[type=reset],
[type=submit] {
-webkit-appearance: button;
}
button:not(:disabled),
[type=button]:not(:disabled),
[type=reset]:not(:disabled),
[type=submit]:not(:disabled) {
cursor: pointer;
}
::-moz-focus-inner {
padding: 0;
border-style: none;
}
textarea {
resize: vertical;
}
fieldset {
min-width: 0;
padding: 0;
margin: 0;
border: 0;
}
legend {
float: right;
width: 100%;
padding: 0;
margin-bottom: 0.5rem;
font-size: calc(1.275rem + 0.3vw);
line-height: inherit;
}
@media (min-width: 1200px) {
legend {
font-size: 1.5rem;
}
}
legend + * {
clear: right;
}
::-webkit-datetime-edit-fields-wrapper,
::-webkit-datetime-edit-text,
::-webkit-datetime-edit-minute,
::-webkit-datetime-edit-hour-field,
::-webkit-datetime-edit-day-field,
::-webkit-datetime-edit-month-field,
::-webkit-datetime-edit-year-field {
padding: 0;
}
::-webkit-inner-spin-button {
height: auto;
}
[type=search] {
outline-offset: -2px;
-webkit-appearance: textfield;
}
[type="tel"],
[type="url"],
[type="email"],
[type="number"] {
direction: ltr;
}
::-webkit-search-decoration {
-webkit-appearance: none;
}
::-webkit-color-swatch-wrapper {
padding: 0;
}
::file-selector-button {
font: inherit;
}
::-webkit-file-upload-button {
font: inherit;
-webkit-appearance: button;
}
output {
display: inline-block;
}
iframe {
border: 0;
}
summary {
display: list-item;
cursor: pointer;
}
progress {
vertical-align: baseline;
}
[hidden] {
display: none !important;
}
/*# sourceMappingURL=bootstrap-reboot.rtl.css.map */

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,8 @@
/*!
* Bootstrap Reboot v5.1.0 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors
* Copyright 2011-2021 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
*/*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;background-color:currentColor;border:0;opacity:.25}hr:not([size]){height:1px}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2}h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){h1{font-size:2.5rem}}h2{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){h2{font-size:2rem}}h3{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){h3{font-size:1.75rem}}h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){h4{font-size:1.5rem}}h5{font-size:1.25rem}h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[data-bs-original-title],abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-right:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-right:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:.875em}mark{padding:.2em;background-color:#fcf8e3}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#0d6efd;text-decoration:underline}a:hover{color:#0a58ca}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em;direction:ltr;unicode-bidi:bidi-override}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:#d63384;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:.875em;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:1em;font-weight:700}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:#6c757d;text-align:right}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]::-webkit-calendar-picker-indicator{display:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:right;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + .3vw);line-height:inherit}@media (min-width:1200px){legend{font-size:1.5rem}}legend+*{clear:right}::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-text,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:textfield}[type=email],[type=number],[type=tel],[type=url]{direction:ltr}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::file-selector-button{font:inherit}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none!important}
/*# sourceMappingURL=bootstrap-reboot.rtl.min.css.map */

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More