diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json deleted file mode 100644 index 45434e736..000000000 --- a/.devcontainer/devcontainer.json +++ /dev/null @@ -1,38 +0,0 @@ -// For format details, see https://aka.ms/devcontainer.json. For config options, see the -// README at: https://github.com/devcontainers/templates/tree/main/src/dotnet -{ - "name": "AccountGo (.NET)", - // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile - "image": "mcr.microsoft.com/devcontainers/dotnet:0-7.0-bullseye", - "features": { - "ghcr.io/devcontainers/features/azure-cli:1": {}, - "ghcr.io/devcontainers/features/git:1": {}, - "ghcr.io/dhoeric/features/google-cloud-cli:1": {}, - "ghcr.io/warrenbuckley/codespace-features/sqlite:1": {}, - "ghcr.io/devcontainers/features/docker-in-docker:1": { - "version": "latest", - "moby": true - }, - "ghcr.io/devcontainers/features/node:1": {} - } - - // Features to add to the dev container. More info: https://containers.dev/features. - // "features": {}, - - // Use 'forwardPorts' to make a list of ports inside the container available locally. - // "forwardPorts": [5000, 5001], - // "portsAttributes": { - // "5001": { - // "protocol": "https" - // } - // } - - // Use 'postCreateCommand' to run commands after the container is created. - // "postCreateCommand": "dotnet restore", - - // Configure tool-specific properties. - // "customizations": {}, - - // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. - // "remoteUser": "root" -} diff --git a/.github/workflows/build-deploy-azure.yml b/.github/workflows/build-deploy-azure.yml deleted file mode 100644 index eb332b2cd..000000000 --- a/.github/workflows/build-deploy-azure.yml +++ /dev/null @@ -1,19 +0,0 @@ -name: Docker Image CI - -on: - push: - branches: [ "main" ] - pull_request: - branches: [ "main" ] - workflow_dispatch: - -jobs: - - build: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - - name: Build the Docker image - run: docker-compose build diff --git a/.github/workflows/gdbapi.yml b/.github/workflows/gdbapi.yml new file mode 100644 index 000000000..03822235b --- /dev/null +++ b/.github/workflows/gdbapi.yml @@ -0,0 +1,91 @@ +# Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy +# More GitHub Actions for Azure: https://github.com/Azure/actions + +name: Build and deploy Good Deed Books API to Azure Web App - gdbapi + +on: + push: + branches: + - main + workflow_dispatch: + +jobs: + build: + runs-on: windows-latest + + steps: + - uses: actions/checkout@v4 + + - name: Set up .NET Core + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '9.x' + + - name: Install dotnet-ef tool + run: | + dotnet tool install --global dotnet-ef + echo "++++ dotnet-ef version" + dotnet ef --version + + - name: Install dotnet aspire workload + run: | + dotnet workload install aspire + + - name: Build with dotnet + run: | + echo "++++ dotnet build" + dotnet build --configuration Release + + - name: Add migrations + run: | + echo "++++ current directory" + pwd + echo "++++ add ApplicationIdentityDbContext migration IdentityMig" + dotnet ef migrations add IdentityMig --project ./src/Api/ --startup-project ./src/Api/Api.csproj --msbuildprojectextensionspath .build/obj/Api/ --context ApplicationIdentityDbContext --output-dir Data/Migrations/IdentityDb + echo "++++ add ApiDbContext migration ApiMig" + dotnet ef migrations add ApiMig --project ./src/Api/ --startup-project ./src/Api/Api.csproj --msbuildprojectextensionspath .build/obj/Api/ --context ApiDbContext --output-dir Data/Migrations/ApiDb + echo "++++ contents of ./src/Api/Data/Migrations/IdentityDb" + ls ./src/Api/Data/Migrations/IdentityDb + echo "++++ contents of ./src/Api/Data/Migrations/ApiDb" + ls ./src/Api/Data/Migrations/ApiDb + + - name: dotnet publish + run: | + echo "++++ contents of dotnet publish ./src/Api/Api.csproj" + dotnet publish ./src/Api/Api.csproj -f net9.0 -c Release -o "${{runner.temp}}/myapp" + + - name: Upload artifact for deployment job + uses: actions/upload-artifact@v4 + with: + name: .net-app + path: ${{runner.temp}}/myapp + + deploy: + runs-on: windows-latest + needs: build + environment: + name: 'Production' + url: ${{ steps.deploy-to-webapp.outputs.webapp-url }} + permissions: + id-token: write #This is required for requesting the JWT + + steps: + - name: Download artifact from build job + uses: actions/download-artifact@v4 + with: + name: .net-app + + - name: Login to Azure + uses: azure/login@v2 + with: + client-id: ${{ secrets.AZUREAPPSERVICE_CLIENTID_A17E281C175C4E629A76134AA823BAC5 }} + tenant-id: ${{ secrets.AZUREAPPSERVICE_TENANTID_258CF23452C24D9795BD94B25EF50B73 }} + subscription-id: ${{ secrets.AZUREAPPSERVICE_SUBSCRIPTIONID_9375B274C69740D39F4770D5D433E8B1 }} + + - name: Deploy to Azure Web App + id: deploy-to-webapp + uses: azure/webapps-deploy@v3 + with: + app-name: 'gdbapi' + slot-name: 'Production' + package: . diff --git a/.github/workflows/gdbmvc_tar.yml b/.github/workflows/gdbmvc_tar.yml new file mode 100644 index 000000000..a45c04e82 --- /dev/null +++ b/.github/workflows/gdbmvc_tar.yml @@ -0,0 +1,96 @@ +# Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy +# More GitHub Actions for Azure: https://github.com/Azure/actions +name: Build and deploy Good Deed Books MVC project to Azure +on: + push: + branches: + - main + workflow_dispatch: +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up .NET Core + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '9.x' + include-prerelease: true + + - name: Install dotnet aspire workload + run: | + dotnet workload install aspire + + - name: Build with dotnet + run: dotnet build --configuration Release + + - name: dotnet publish + run: dotnet publish ./src/AccountGoWeb/AccountGoWeb.csproj -c Release -o ${{runner.temp}}/myapp + + - name: Archive production artifacts + run: | + echo "+++++++++++++++++++++++++ where am I? ++++++++++++++++++++++++" + pwd + echo "+++++++++++++++++++++++++ save current directory into a variable dir ++++" + dir=$(pwd) + echo "+++++++++ what is in variable dir ++++++++++++++" + echo $dir + echo "++++++++++++++++++++++++ what's in current directory? ++++++++" + ls -al + echo "+++++ what's in the ${{runner.temp}}/myapp directory? ++++" + ls -al ${{runner.temp}}/myapp + echo "+++++ change directory to ${{runner.temp}}/myapp ++++" + cd ${{runner.temp}}/myapp + echo "+++++++++++++++++++++++++ where am I? ++++++++++++++++++++++++" + pwd + echo "+++++++++++++++++++++++++ compress current directory and save in $dir/my_artifact.tar.gz ++++" + tar -czvf $dir/my_artifact.tar.gz . + echo "+++++++++++++++++++++++++ change back to $dir directory ++++" + cd $dir + echo "++++++++++++++++++++++++ what's in $dir directory? ++++++++" + ls -al + + - name: Upload artifact for deployment job + uses: actions/upload-artifact@v4 + with: + name: .net-app + path: my_artifact.tar.gz + + deploy: + runs-on: ubuntu-latest + needs: build + environment: + name: 'Production' + url: ${{ steps.deploy-to-webapp.outputs.webapp-url }} + permissions: + id-token: write #This is required for requesting the JWT + + steps: + - name: Download artifact from build job + uses: actions/download-artifact@v4 + with: + name: .net-app + + - name: Login to Azure + uses: azure/login@v2 + with: + client-id: ${{ secrets.AZUREAPPSERVICE_CLIENTID_8B6389BB3F37413FB2483AC2574C3BCB }} + tenant-id: ${{ secrets.AZUREAPPSERVICE_TENANTID_FD62C59DE5DC42C2A07DB8191A522348 }} + subscription-id: ${{ secrets.AZUREAPPSERVICE_SUBSCRIPTIONID_7076EF307FDA4C11BC99A0A7A0943794 }} + + - name: Extract artifacts + run: | + tar -xzvf my_artifact.tar.gz -C . + + - name: Set startup command + run: | + az webapp config set --resource-group goodbooks-RG --name gdbmvc --startup-file "dotnet /home/site/wwwroot/GoodBooks.dll" + + - name: Deploy to Azure Web App + id: deploy-to-webapp + uses: azure/webapps-deploy@v3 + with: + app-name: 'gdbmvc' + slot-name: 'Production' + package: . diff --git a/.gitignore b/.gitignore index fbb3738a8..6272404dc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,9 @@ ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. +# custom 2024/04/29 +.idea + # User-specific files *.suo *.user @@ -18,6 +21,7 @@ build/ bld/ [Bb]in/ [Oo]bj/ +node_modules/ # Roslyn cache directories *.ide/ @@ -186,6 +190,10 @@ FakesAssemblies/ # Lib folder generated by gulpfile.js **/src/[Ww]eb[Aa]ngular/wwwroot/[Ll]ib/* + + +**/src/[Rr]eact[Ff]ront[Ee]nd/wwwroot/* + **/src/[Ww]eb[Aa]pp/wwwroot/app/scripts/* **/src/[Ww]eb[Aa]pp/wwwroot/app/compiledscripts/* **/src/[Ww]eb[Aa]pp/wwwroot/app/typescripts/compiledscripts/* @@ -215,7 +223,8 @@ FakesAssemblies/ /src/Api/Plugins/* /src/AccountGoWeb/Modules/* /src/AccountGoWeb/Plugins/* -/src/Api/Data/Migrations +# /src/Api/Data/Migrations .vscode -exclude \ No newline at end of file +exclude +/src/Api/appsettings.Development.json diff --git a/accountgo.sln b/accountgo.sln index 4eaa3f47d..becf77c72 100644 --- a/accountgo.sln +++ b/accountgo.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.26228.4 +# Visual Studio Version 17 +VisualStudioVersion = 17.8.34322.80 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Presentation", "Presentation", "{0295DFAC-BF6E-46C0-A63D-FBE9AF3C04E5}" EndProject @@ -19,19 +19,33 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AccountGoWeb", "src\Account EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dto", "src\Dto\Dto.csproj", "{1E610F55-2D74-4856-818B-0D0B47601B75}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{E1B45442-3F2D-491A-9D8A-0DDA50309A1A}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Infrastructure", "src\Infrastructure\Infrastructure.csproj", "{EBFAFB5B-494F-48D5-A70D-AF1490B9260A}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{0EAC5155-A5EA-49C1-8E0C-19DD36D2C21C}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Module.Tests", "test\Module.Tests\Module.Tests.csproj", "{54631590-2A41-45F4-B057-92C840ED08C1}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Modules", "Modules", "{E0861852-0F5B-4810-8586-A59038BC4034}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SampleNetStandard20", "test\SampleModules\SampleNetStandard20\SampleNetStandard20.csproj", "{B0AB6EA7-7D53-4457-9482-F0613F99E3BB}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SampleModule", "src\Modules\SampleModule\SampleModule.csproj", "{B296277A-C822-444E-8CFA-4CC4C1C1F737}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{EF0BD6F1-00D6-41E5-91AB-8B606D35D448}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SampleNetStandard20", "test\SampleModules\SampleNetStandard20\SampleNetStandard20.csproj", "{B0AB6EA7-7D53-4457-9482-F0613F99E3BB}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Modules", "Modules", "{EFF13E33-1D79-4221-87D7-4FCC8EA88943}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SampleModule", "src\Modules\SampleModule\SampleModule.csproj", "{ABD1EE97-DD84-4C6A-8F3F-28E7D3D898B4}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazorGDB", "src\BlazorGDB\BlazorGDB\BlazorGDB.csproj", "{AB5F238F-AB78-4A85-8D8D-17E211015FD3}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BlazorGDB.Client", "src\BlazorGDB\BlazorGDB.Client\BlazorGDB.Client.csproj", "{12BE663C-C0DD-4343-93DF-6B2D853B6B79}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibraryGDB", "src\LibraryGDB\LibraryGDB.csproj", "{F64790E0-86AD-4562-9AC5-F4DD3F4881BA}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Aspire", "Aspire", "{64880D93-BAB4-FF83-898C-B934B68C31A9}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "src.ServiceDefaults", "src\src.ServiceDefaults\src.ServiceDefaults.csproj", "{949C95E9-4261-416E-8D2A-F05E3D4640CA}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "src.AppHost", "src\src.AppHost\src.AppHost.csproj", "{ADDBCE30-FE7F-4198-8A37-772EF6BF3676}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MigrationService", "src\MigrationService\MigrationService.csproj", "{DF084D96-707B-47C2-9493-85FA84631ACE}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -67,14 +81,38 @@ Global {54631590-2A41-45F4-B057-92C840ED08C1}.Debug|Any CPU.Build.0 = Debug|Any CPU {54631590-2A41-45F4-B057-92C840ED08C1}.Release|Any CPU.ActiveCfg = Release|Any CPU {54631590-2A41-45F4-B057-92C840ED08C1}.Release|Any CPU.Build.0 = Release|Any CPU - {B296277A-C822-444E-8CFA-4CC4C1C1F737}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B296277A-C822-444E-8CFA-4CC4C1C1F737}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B296277A-C822-444E-8CFA-4CC4C1C1F737}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B296277A-C822-444E-8CFA-4CC4C1C1F737}.Release|Any CPU.Build.0 = Release|Any CPU {B0AB6EA7-7D53-4457-9482-F0613F99E3BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {B0AB6EA7-7D53-4457-9482-F0613F99E3BB}.Debug|Any CPU.Build.0 = Debug|Any CPU {B0AB6EA7-7D53-4457-9482-F0613F99E3BB}.Release|Any CPU.ActiveCfg = Release|Any CPU {B0AB6EA7-7D53-4457-9482-F0613F99E3BB}.Release|Any CPU.Build.0 = Release|Any CPU + {ABD1EE97-DD84-4C6A-8F3F-28E7D3D898B4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ABD1EE97-DD84-4C6A-8F3F-28E7D3D898B4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ABD1EE97-DD84-4C6A-8F3F-28E7D3D898B4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ABD1EE97-DD84-4C6A-8F3F-28E7D3D898B4}.Release|Any CPU.Build.0 = Release|Any CPU + {AB5F238F-AB78-4A85-8D8D-17E211015FD3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AB5F238F-AB78-4A85-8D8D-17E211015FD3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AB5F238F-AB78-4A85-8D8D-17E211015FD3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AB5F238F-AB78-4A85-8D8D-17E211015FD3}.Release|Any CPU.Build.0 = Release|Any CPU + {12BE663C-C0DD-4343-93DF-6B2D853B6B79}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {12BE663C-C0DD-4343-93DF-6B2D853B6B79}.Debug|Any CPU.Build.0 = Debug|Any CPU + {12BE663C-C0DD-4343-93DF-6B2D853B6B79}.Release|Any CPU.ActiveCfg = Release|Any CPU + {12BE663C-C0DD-4343-93DF-6B2D853B6B79}.Release|Any CPU.Build.0 = Release|Any CPU + {F64790E0-86AD-4562-9AC5-F4DD3F4881BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F64790E0-86AD-4562-9AC5-F4DD3F4881BA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F64790E0-86AD-4562-9AC5-F4DD3F4881BA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F64790E0-86AD-4562-9AC5-F4DD3F4881BA}.Release|Any CPU.Build.0 = Release|Any CPU + {949C95E9-4261-416E-8D2A-F05E3D4640CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {949C95E9-4261-416E-8D2A-F05E3D4640CA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {949C95E9-4261-416E-8D2A-F05E3D4640CA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {949C95E9-4261-416E-8D2A-F05E3D4640CA}.Release|Any CPU.Build.0 = Release|Any CPU + {ADDBCE30-FE7F-4198-8A37-772EF6BF3676}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ADDBCE30-FE7F-4198-8A37-772EF6BF3676}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ADDBCE30-FE7F-4198-8A37-772EF6BF3676}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ADDBCE30-FE7F-4198-8A37-772EF6BF3676}.Release|Any CPU.Build.0 = Release|Any CPU + {DF084D96-707B-47C2-9493-85FA84631ACE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DF084D96-707B-47C2-9493-85FA84631ACE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DF084D96-707B-47C2-9493-85FA84631ACE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DF084D96-707B-47C2-9493-85FA84631ACE}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -84,11 +122,18 @@ Global {C02DECC9-2A82-42C0-8F26-D0AE6559AC5E} = {B4CE3CD4-74AA-4A22-B514-BC9B380AAFD7} {09096FEC-DA29-4914-B046-CD280220C52A} = {0295DFAC-BF6E-46C0-A63D-FBE9AF3C04E5} {9CA13D2D-D6E2-4201-946C-81D1E6093404} = {0295DFAC-BF6E-46C0-A63D-FBE9AF3C04E5} - {1E610F55-2D74-4856-818B-0D0B47601B75} = {0295DFAC-BF6E-46C0-A63D-FBE9AF3C04E5} + {1E610F55-2D74-4856-818B-0D0B47601B75} = {EF0BD6F1-00D6-41E5-91AB-8B606D35D448} {EBFAFB5B-494F-48D5-A70D-AF1490B9260A} = {B5D35D0C-387C-44FA-9A70-6FE24DAE5728} {54631590-2A41-45F4-B057-92C840ED08C1} = {0EAC5155-A5EA-49C1-8E0C-19DD36D2C21C} - {B296277A-C822-444E-8CFA-4CC4C1C1F737} = {E0861852-0F5B-4810-8586-A59038BC4034} {B0AB6EA7-7D53-4457-9482-F0613F99E3BB} = {0EAC5155-A5EA-49C1-8E0C-19DD36D2C21C} + {EFF13E33-1D79-4221-87D7-4FCC8EA88943} = {EF0BD6F1-00D6-41E5-91AB-8B606D35D448} + {ABD1EE97-DD84-4C6A-8F3F-28E7D3D898B4} = {EFF13E33-1D79-4221-87D7-4FCC8EA88943} + {AB5F238F-AB78-4A85-8D8D-17E211015FD3} = {0295DFAC-BF6E-46C0-A63D-FBE9AF3C04E5} + {12BE663C-C0DD-4343-93DF-6B2D853B6B79} = {0295DFAC-BF6E-46C0-A63D-FBE9AF3C04E5} + {F64790E0-86AD-4562-9AC5-F4DD3F4881BA} = {B5D35D0C-387C-44FA-9A70-6FE24DAE5728} + {949C95E9-4261-416E-8D2A-F05E3D4640CA} = {64880D93-BAB4-FF83-898C-B934B68C31A9} + {ADDBCE30-FE7F-4198-8A37-772EF6BF3676} = {64880D93-BAB4-FF83-898C-B934B68C31A9} + {DF084D96-707B-47C2-9493-85FA84631ACE} = {B4CE3CD4-74AA-4A22-B514-BC9B380AAFD7} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {AD284F35-E81F-4678-B737-A5DC8CB883CB} diff --git a/actions/endpoint_sahil_gdbapi.yml.20241204 b/actions/endpoint_sahil_gdbapi.yml.20241204 new file mode 100644 index 000000000..94f4b0fbd --- /dev/null +++ b/actions/endpoint_sahil_gdbapi.yml.20241204 @@ -0,0 +1,87 @@ +# Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy +# More GitHub Actions for Azure: https://github.com/Azure/actions + +name: Build and deploy Good Deed Books API to Azure Web App - gdbapi + +on: + push: + branches: + - endpoint_sahil + workflow_dispatch: + +jobs: + build: + runs-on: windows-latest + + steps: + - uses: actions/checkout@v4 + + - name: Set up .NET Core + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '8.x' + + - name: Install dotnet-ef tool + run: | + dotnet tool install --global dotnet-ef + echo "++++ dotnet-ef version" + dotnet ef --version + + - name: Build with dotnet + run: | + echo "++++ dotnet build" + dotnet build --configuration Release + + - name: Add migrations + run: | + echo "++++ current directory" + pwd + echo "++++ add ApplicationIdentityDbContext migration M1" + dotnet ef migrations add M1 --project ./src/Api/ --startup-project ./src/Api/Api.csproj --msbuildprojectextensionspath .build/obj/Api/ --context ApplicationIdentityDbContext --output-dir Data/Migrations/IdentityDb + echo "++++ add ApiDbContext migration M2" + dotnet ef migrations add M2 --project ./src/Api/ --startup-project ./src/Api/Api.csproj --msbuildprojectextensionspath .build/obj/Api/ --context ApiDbContext --output-dir Data/Migrations/ApiDb + echo "++++ contents of ./src/Api/Data/Migrations/IdentityDb" + ls ./src/Api/Data/Migrations/IdentityDb + echo "++++ contents of ./src/Api/Data/Migrations/ApiDb" + ls ./src/Api/Data/Migrations/ApiDb + + - name: dotnet publish + run: | + echo "++++ contents of dotnet publish ./src/Api/Api.csproj" + dotnet publish ./src/Api/Api.csproj -f net8.0 -c Release -o "${{runner.temp}}/myapp" + + - name: Upload artifact for deployment job + uses: actions/upload-artifact@v4 + with: + name: .net-app + path: ${{runner.temp}}/myapp + + deploy: + runs-on: windows-latest + needs: build + environment: + name: 'Production' + url: ${{ steps.deploy-to-webapp.outputs.webapp-url }} + permissions: + id-token: write #This is required for requesting the JWT + + steps: + - name: Download artifact from build job + uses: actions/download-artifact@v4 + with: + name: .net-app + + - name: Login to Azure + uses: azure/login@v2 + with: + client-id: ${{ secrets.AZUREAPPSERVICE_CLIENTID_A17E281C175C4E629A76134AA823BAC5 }} + tenant-id: ${{ secrets.AZUREAPPSERVICE_TENANTID_258CF23452C24D9795BD94B25EF50B73 }} + subscription-id: ${{ secrets.AZUREAPPSERVICE_SUBSCRIPTIONID_9375B274C69740D39F4770D5D433E8B1 }} + + - name: Deploy to Azure Web App + id: deploy-to-webapp + uses: azure/webapps-deploy@v3 + with: + app-name: 'gdbapi' + slot-name: 'Production' + package: . diff --git a/actions/endpoint_sahil_gdbmvc.yml.20241204 b/actions/endpoint_sahil_gdbmvc.yml.20241204 new file mode 100644 index 000000000..330b665ab --- /dev/null +++ b/actions/endpoint_sahil_gdbmvc.yml.20241204 @@ -0,0 +1,101 @@ +# Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy +# More GitHub Actions for Azure: https://github.com/Azure/actions + +name: Build and deploy Good Deed Books MVC project to Azure + +on: + push: + branches: + - endpoint_sahil + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Set up .NET Core + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '8.x' + include-prerelease: true + + - name: Build with dotnet + run: dotnet build --configuration Release + + - name: dotnet publish + run: dotnet publish ./src/AccountGoWeb/AccountGoWeb.csproj -c Release -o ${{env.DOTNET_ROOT}}/myapp + + - name: Archive production artifacts + run: | + echo "+++++++++++++++++++++++++ where am I? ++++++++++++++++++++++++" + pwd + echo "+++++++++++++++++++++++++ save current directory into a variable dir ++++" + dir=$(pwd) + echo "+++++++++ what is in variable dir ++++++++++++++" + echo $dir + echo "++++++++++++++++++++++++ what's in current directory? ++++++++" + ls -al + echo "+++++ what's in the ${{env.DOTNET_ROOT}}/myapp directory? ++++" + ls -al ${{env.DOTNET_ROOT}}/myapp + echo "+++++ change directoiry to ${{env.DOTNET_ROOT}}/myapp ++++" + cd ${{env.DOTNET_ROOT}}/myapp + echo "+++++++++++++++++++++++++ where am I? ++++++++++++++++++++++++" + pwd + echo "+++++++++++++++++++++++++ compress current directory and save in $dir/my_artifact.tar.gz ++++" + tar -czvf $dir/my_artifact.tar.gz . + echo "+++++++++++++++++++++++++ change dir to to $dir directory ++++" + cd $dir + echo "+++++++++++++++++++++++++ where am I? ++++++++++++++++++++++++" + pwd + echo "++++++++++++++++++++++++ what's in $dir directory? ++++++++" + ls -al + + - name: Upload artifact for deployment job + uses: actions/upload-artifact@v4 + with: + name: .net-app + path: my_artifact.tar.gz + + deploy: + runs-on: ubuntu-latest + needs: build + environment: + name: 'Production' + url: ${{ steps.deploy-to-webapp.outputs.webapp-url }} + permissions: + id-token: write #This is required for requesting the JWT + + steps: + - name: Download artifact from build job + uses: actions/download-artifact@v4 + with: + name: .net-app + + - name: Login to Azure + uses: azure/login@v2 + with: + client-id: ${{ secrets.AZUREAPPSERVICE_CLIENTID_8B6389BB3F37413FB2483AC2574C3BCB }} + tenant-id: ${{ secrets.AZUREAPPSERVICE_TENANTID_FD62C59DE5DC42C2A07DB8191A522348 }} + subscription-id: ${{ secrets.AZUREAPPSERVICE_SUBSCRIPTIONID_7076EF307FDA4C11BC99A0A7A0943794 }} + + - name: Extract artifacts + run: | + tar -xzvf my_artifact.tar.gz -C . + + - name: Print working directory + run: pwd + + - name: List directory contents + run: ls -l /home/runner/.dotnet/ + + - name: Deploy to Azure Web App + id: deploy-to-webapp + uses: azure/webapps-deploy@v3 + with: + app-name: 'gdbmvc' + slot-name: 'Production' + package: . + \ No newline at end of file diff --git a/actions/gdb-blazor.yml.gold b/actions/gdb-blazor.yml.gold new file mode 100644 index 000000000..7691040f1 --- /dev/null +++ b/actions/gdb-blazor.yml.gold @@ -0,0 +1,76 @@ +# Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy +# More GitHub Actions for Azure: https://github.com/Azure/actions + +name: Build and deploy Good Deed Books BLAZOR project to Azure + +on: + push: + branches: + - endpoint_sahil + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Set up .NET Core + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '8.x' + + - name: Build with dotnet + working-directory: ./src/BlazorGDB/BlazorGDB + run: dotnet build --configuration Release + + - name: dotnet publish + working-directory: ./src/BlazorGDB/BlazorGDB + run: dotnet publish BlazorGDB.csproj -c Release -o ${{env.DOTNET_ROOT}}/myapp + + - name: sanity check + run: | + echo "+++++++++++++++++++++++++ where am I? ++++++++++++++++++++++++" + pwd + echo "++++++++++++++++++++++++ what's in current directory? ++++++++" + ls -al + echo "+++++ what's in the ${{env.DOTNET_ROOT}}/myapp directory? ++++" + ls -al ${{env.DOTNET_ROOT}}/myapp + + - name: Upload artifact for deployment job + uses: actions/upload-artifact@v4 + with: + name: .net-app + path: ${{env.DOTNET_ROOT}}/myapp + + deploy: + runs-on: ubuntu-latest + needs: build + environment: + name: 'Production' + url: ${{ steps.deploy-to-webapp.outputs.webapp-url }} + permissions: + id-token: write #This is required for requesting the JWT + + steps: + - name: Download artifact from build job + uses: actions/download-artifact@v4 + with: + name: .net-app + + - name: Login to Azure + uses: azure/login@v2 + with: + client-id: ${{ secrets.AZUREAPPSERVICE_CLIENTID_6A854C1CD0C74473AD2E3B9F843CC396 }} + tenant-id: ${{ secrets.AZUREAPPSERVICE_TENANTID_224A065E650B4D5F9EB2329B6B2F1716 }} + subscription-id: ${{ secrets.AZUREAPPSERVICE_SUBSCRIPTIONID_570B031F0942445C8E479905EE706F43 }} + + - name: Deploy to Azure Web App + id: deploy-to-webapp + uses: azure/webapps-deploy@v3 + with: + app-name: 'gdb-blazor' + slot-name: 'Production' + package: . + \ No newline at end of file diff --git a/actions/gdb_api.yml.flat b/actions/gdb_api.yml.flat new file mode 100644 index 000000000..9218db27d --- /dev/null +++ b/actions/gdb_api.yml.flat @@ -0,0 +1,91 @@ +# Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy +# More GitHub Actions for Azure: https://github.com/Azure/actions + +name: Build and deploy Good Deed Books API project to Azure + +on: + push: + branches: + - endpoint_sahil + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Set up .NET Core + uses: actions/setup-dotnet@v1 + with: + dotnet-version: '8.x' + include-prerelease: true + + - name: Install dotnet-ef tool + run: | + dotnet tool install --global dotnet-ef + echo "++++ dotnet-ef version" + dotnet ef --version + + - name: Build with dotnet + run: | + echo "++++ dotnet restore" + dotnet restore + echo "++++ dotnet build" + dotnet build --configuration Release + + - name: Add migrations + run: | + echo "++++ current directory" + pwd + echo "++++ add ApplicationIdentityDbContext migration M1" + dotnet ef migrations add M1 --project ./src/Api/ --startup-project ./src/Api/Api.csproj --msbuildprojectextensionspath .build/obj/Api/ --context ApplicationIdentityDbContext --output-dir Data/Migrations/IdentityDb + echo "++++ add ApiDbContext migration M2" + dotnet ef migrations add M2 --project ./src/Api/ --startup-project ./src/Api/Api.csproj --msbuildprojectextensionspath .build/obj/Api/ --context ApiDbContext --output-dir Data/Migrations/ApiDb + echo "++++ contents of ./src/Api/Data/Migrations/IdentityDb" + ls ./src/Api/Data/Migrations/IdentityDb + echo "++++ contents of ./src/Api/Data/Migrations/ApiDb" + ls ./src/Api/Data/Migrations/ApiDb + + - name: dotnet publish + run: | + echo "++++ contents of dotnet publish ./src/Api/Api.csproj" + dotnet publish ./src/Api/Api.csproj -c Release -o ${{env.DOTNET_ROOT}}/myapp + + - name: Upload artifact for deployment job + uses: actions/upload-artifact@v3 + with: + name: .net-app + path: ${{env.DOTNET_ROOT}}/myapp + + deploy: + runs-on: ubuntu-latest + needs: build + environment: + name: 'Production' + url: ${{ steps.deploy-to-webapp.outputs.webapp-url }} + permissions: + id-token: write #This is required for requesting the JWT + + steps: + - name: Download artifact from build job + uses: actions/download-artifact@v3 + with: + name: .net-app + + - name: Login to Azure + uses: azure/login@v1 + with: + client-id: ${{ secrets.AZUREAPPSERVICE_CLIENTID_543326D87AEF459D91E15D756166A5AC }} + tenant-id: ${{ secrets.AZUREAPPSERVICE_TENANTID_D57EB2BACAA54EE2AB97F696E8E99A4B }} + subscription-id: ${{ secrets.AZUREAPPSERVICE_SUBSCRIPTIONID_3C797712E9A047958FF5C9BB540F0543 }} + + - name: Deploy to Azure Web App + id: deploy-to-webapp + uses: azure/webapps-deploy@v2 + with: + app-name: 'goodbooksapi' + slot-name: 'Production' + package: . + diff --git a/actions/gdb_mvc_tar.yml.flat b/actions/gdb_mvc_tar.yml.flat new file mode 100644 index 000000000..0b749010a --- /dev/null +++ b/actions/gdb_mvc_tar.yml.flat @@ -0,0 +1,101 @@ +# Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy +# More GitHub Actions for Azure: https://github.com/Azure/actions + +name: Build and deploy Good Deed Books MVC project to Azure + +on: + push: + branches: + - endpoint_sahil + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Set up .NET Core + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '8.x' + include-prerelease: true + + - name: Build with dotnet + run: dotnet build --configuration Release + + - name: dotnet publish + run: dotnet publish ./src/AccountGoWeb/AccountGoWeb.csproj -c Release -o ${{env.DOTNET_ROOT}}/myapp + + - name: Archive production artifacts + run: | + echo "+++++++++++++++++++++++++ where am I? ++++++++++++++++++++++++" + pwd + echo "+++++++++++++++++++++++++ save current directory into a variable dir ++++" + dir=$(pwd) + echo "+++++++++ what is in variable dir ++++++++++++++" + echo $dir + echo "++++++++++++++++++++++++ what's in current directory? ++++++++" + ls -al + echo "+++++ what's in the ${{env.DOTNET_ROOT}}/myapp directory? ++++" + ls -al ${{env.DOTNET_ROOT}}/myapp + echo "+++++ change directoiry to ${{env.DOTNET_ROOT}}/myapp ++++" + cd ${{env.DOTNET_ROOT}}/myapp + echo "+++++++++++++++++++++++++ where am I? ++++++++++++++++++++++++" + pwd + echo "+++++++++++++++++++++++++ compress current directory and save in $dir/my_artifact.tar.gz ++++" + tar -czvf $dir/my_artifact.tar.gz . + echo "+++++++++++++++++++++++++ change dir to to $dir directory ++++" + cd $dir + echo "+++++++++++++++++++++++++ where am I? ++++++++++++++++++++++++" + pwd + echo "++++++++++++++++++++++++ what's in $dir directory? ++++++++" + ls -al + + - name: Upload artifact for deployment job + uses: actions/upload-artifact@v4 + with: + name: .net-app + path: my_artifact.tar.gz + + deploy: + runs-on: ubuntu-latest + needs: build + environment: + name: 'Production' + url: ${{ steps.deploy-to-webapp.outputs.webapp-url }} + permissions: + id-token: write #This is required for requesting the JWT + + steps: + - name: Download artifact from build job + uses: actions/download-artifact@v4 + with: + name: .net-app + + - name: Login to Azure + uses: azure/login@v2 + with: + client-id: ${{ secrets.AZUREAPPSERVICE_CLIENTID_28108B2CCE81480BB0295B2554B37231 }} + tenant-id: ${{ secrets.AZUREAPPSERVICE_TENANTID_9ED1B649A03F45E7B34C3BE1217B6BDE }} + subscription-id: ${{ secrets.AZUREAPPSERVICE_SUBSCRIPTIONID_A41842A963384E4BAB26580EEFE65E92 }} + + - name: Extract artifacts + run: | + tar -xzvf my_artifact.tar.gz -C . + + - name: Print working directory + run: pwd + + - name: List directory contents + run: ls -l /home/runner/.dotnet/ + + - name: Deploy to Azure Web App + id: deploy-to-webapp + uses: azure/webapps-deploy@v3 + with: + app-name: 'good-books' + slot-name: 'Production' + package: . + diff --git a/actions/gdbblazor.yml b/actions/gdbblazor.yml new file mode 100644 index 000000000..a372a08c3 --- /dev/null +++ b/actions/gdbblazor.yml @@ -0,0 +1,67 @@ +# Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy +# More GitHub Actions for Azure: https://github.com/Azure/actions + +name: Build and deploy Good Deed Books BLAZOR project to Azure + +on: + push: + branches: + - endpoint_sahil + +jobs: + build: + runs-on: windows-latest + + steps: + - uses: actions/checkout@v2 + + - name: Set up .NET Core + uses: actions/setup-dotnet@v2 + with: + dotnet-version: '8.0.x' + + - name: Restore dependencies + run: dotnet restore ./src/BlazorGDB/BlazorGDB/BlazorGDB.csproj + + - name: Build + run: dotnet build ./src/BlazorGDB/BlazorGDB/BlazorGDB.csproj --configuration Release + + - name: Publish + run: dotnet publish ./src/BlazorGDB/BlazorGDB/BlazorGDB.csproj --configuration Release --output ${{ github.workspace }}/myapp + + - name: Upload artifact for deployment job + uses: actions/upload-artifact@v3 + with: + name: .net-app + path: ${{ github.workspace }}/myapp + + deploy: + runs-on: windows-latest + needs: build + environment: + name: 'Production' + url: ${{ steps.deploy-to-webapp.outputs.webapp-url }} + permissions: + id-token: write #This is required for requesting the JWT + + steps: + - name: Download artifact from build job + uses: actions/download-artifact@v3 + with: + name: .net-app + + - name: Login to Azure + uses: azure/login@v2 + with: + client-id: ${{ secrets.AZUREAPPSERVICE_CLIENTID_C7C01847F7FC4BBFB72DEAC64242E5A4 }} + tenant-id: ${{ secrets.AZUREAPPSERVICE_TENANTID_21069DC407434A3591399953BE45ED78 }} + subscription-id: ${{ secrets.AZUREAPPSERVICE_SUBSCRIPTIONID_CC5D4E473B8345BA854EA230A48D8D20 }} + + - name: Deploy to Azure Web App + id: deploy-to-webapp + uses: azure/webapps-deploy@v3 + with: + app-name: 'gdbblazor' + slot-name: 'Production' + package: . + diff --git a/actions/good-books_mvc.yml.disable b/actions/good-books_mvc.yml.disable new file mode 100644 index 000000000..659083c9a --- /dev/null +++ b/actions/good-books_mvc.yml.disable @@ -0,0 +1,75 @@ +# Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy +# More GitHub Actions for Azure: https://github.com/Azure/actions + +name: Build and deploy GoodBooks MVC project to Azure + +on: + push: + branches: + - endpoint_sahil + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Set up .NET Core + uses: actions/setup-dotnet@v1 + with: + dotnet-version: '8.x' + include-prerelease: true + + - name: Build with dotnet + run: dotnet build --configuration Release + + - name: dotnet publish + run: dotnet publish ./src/AccountGoWeb/AccountGoWeb.csproj -c Release -o ${{env.DOTNET_ROOT}}/myapp + + # - name: Archive production artifacts + # run: | + # tar -czvf my_artifact.tar.gz ${{env.DOTNET_ROOT}}/myapp + + - name: Upload artifact for deployment job + uses: actions/upload-artifact@v3 + with: + name: .net-app + # path: my_artifact.tar.gz + path: ${{env.DOTNET_ROOT}}/myapp + + deploy: + runs-on: ubuntu-latest + needs: build + environment: + name: 'Production' + url: ${{ steps.deploy-to-webapp.outputs.webapp-url }} + permissions: + id-token: write #This is required for requesting the JWT + + steps: + - name: Download artifact from build job + uses: actions/download-artifact@v3 + with: + name: .net-app + + - name: Login to Azure + uses: azure/login@v1 + with: + client-id: ${{ secrets.AZUREAPPSERVICE_CLIENTID_28108B2CCE81480BB0295B2554B37231 }} + tenant-id: ${{ secrets.AZUREAPPSERVICE_TENANTID_9ED1B649A03F45E7B34C3BE1217B6BDE }} + subscription-id: ${{ secrets.AZUREAPPSERVICE_SUBSCRIPTIONID_A41842A963384E4BAB26580EEFE65E92 }} + + # - name: Extract artifacts + # run: | + # tar -xzvf my_artifact.tar.gz -C . + + - name: Deploy to Azure Web App + id: deploy-to-webapp + uses: azure/webapps-deploy@v2 + with: + app-name: 'good-books' + slot-name: 'Production' + package: . + diff --git a/actions/good-books_react.yml.disable b/actions/good-books_react.yml.disable new file mode 100644 index 000000000..99103e5e5 --- /dev/null +++ b/actions/good-books_react.yml.disable @@ -0,0 +1,54 @@ +name: Azure Static Web Apps CI/CD + +on: + push: + branches: + - endpoint_sahil + pull_request: + types: [opened, synchronize, reopened, closed] + branches: + - endpoint_sahil + +jobs: + build_and_deploy_job: + if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed') + runs-on: ubuntu-latest + name: Build and Deploy Job + steps: + - uses: actions/checkout@v3 + with: + submodules: true + lfs: false + + - name: Replace API URL + run: | + echo "++++ search & replace API URL from http://localhost:8001 to https://goodbooksapi.azurewebsites.net" + sed -i 's|http://localhost:8001|https://goodbooksapi.azurewebsites.net|g' ./src/GoodBooksReact/src/components/Shared/Config/index.tsx + echo "++++ display contents of index.tsx after search & replace" + cat ./src/GoodBooksReact/src/components/Shared/Config/index.tsx + + - name: Build And Deploy + id: builddeploy + uses: Azure/static-web-apps-deploy@v1 + with: + azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_MANGO_GLACIER_0EDFEC41E }} + repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for Github integrations (i.e. PR comments) + action: "upload" + ###### Repository/Build Configurations - These values can be configured to match your app requirements. ###### + # For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig + app_location: "/src/GoodBooksReact/" # App source code path + api_location: "" # Api source code path - optional + output_location: "/dist" # Built app content directory - optional + ###### End of Repository/Build Configurations ###### + + close_pull_request_job: + if: github.event_name == 'pull_request' && github.event.action == 'closed' + runs-on: ubuntu-latest + name: Close Pull Request Job + steps: + - name: Close Pull Request + id: closepullrequest + uses: Azure/static-web-apps-deploy@v1 + with: + azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_MANGO_GLACIER_0EDFEC41E }} + action: "close" diff --git a/actions/mvc_tar.yml.works b/actions/mvc_tar.yml.works new file mode 100644 index 000000000..0e57f5cfc --- /dev/null +++ b/actions/mvc_tar.yml.works @@ -0,0 +1,92 @@ +# Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy +# More GitHub Actions for Azure: https://github.com/Azure/actions +name: Build and deploy Good Deed Books MVC project to Azure +on: + push: + branches: + - endpoint_sahil + workflow_dispatch: +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up .NET Core + uses: actions/setup-dotnet@v4 + with: + dotnet-version: '8.x' + include-prerelease: true + + - name: Build with dotnet + run: dotnet build --configuration Release + + - name: dotnet publish + run: dotnet publish ./src/AccountGoWeb/AccountGoWeb.csproj -c Release -o ${{runner.temp}}/myapp + + - name: Archive production artifacts + run: | + echo "+++++++++++++++++++++++++ where am I? ++++++++++++++++++++++++" + pwd + echo "+++++++++++++++++++++++++ save current directory into a variable dir ++++" + dir=$(pwd) + echo "+++++++++ what is in variable dir ++++++++++++++" + echo $dir + echo "++++++++++++++++++++++++ what's in current directory? ++++++++" + ls -al + echo "+++++ what's in the ${{runner.temp}}/myapp directory? ++++" + ls -al ${{runner.temp}}/myapp + echo "+++++ change directory to ${{runner.temp}}/myapp ++++" + cd ${{runner.temp}}/myapp + echo "+++++++++++++++++++++++++ where am I? ++++++++++++++++++++++++" + pwd + echo "+++++++++++++++++++++++++ compress current directory and save in $dir/my_artifact.tar.gz ++++" + tar -czvf $dir/my_artifact.tar.gz . + echo "+++++++++++++++++++++++++ change back to $dir directory ++++" + cd $dir + echo "++++++++++++++++++++++++ what's in $dir directory? ++++++++" + ls -al + + - name: Upload artifact for deployment job + uses: actions/upload-artifact@v4 + with: + name: .net-app + path: my_artifact.tar.gz + + deploy: + runs-on: ubuntu-latest + needs: build + environment: + name: 'Production' + url: ${{ steps.deploy-to-webapp.outputs.webapp-url }} + permissions: + id-token: write #This is required for requesting the JWT + + steps: + - name: Download artifact from build job + uses: actions/download-artifact@v4 + with: + name: .net-app + + - name: Login to Azure + uses: azure/login@v2 + with: + client-id: ${{ secrets.AZUREAPPSERVICE_CLIENTID_8B6389BB3F37413FB2483AC2574C3BCB }} + tenant-id: ${{ secrets.AZUREAPPSERVICE_TENANTID_FD62C59DE5DC42C2A07DB8191A522348 }} + subscription-id: ${{ secrets.AZUREAPPSERVICE_SUBSCRIPTIONID_7076EF307FDA4C11BC99A0A7A0943794 }} + + - name: Extract artifacts + run: | + tar -xzvf my_artifact.tar.gz -C . + + - name: Set startup command + run: | + az webapp config set --resource-group goodbooks-RG --name gdbmvc --startup-file "dotnet /home/site/wwwroot/GoodBooks.dll" + + - name: Deploy to Azure Web App + id: deploy-to-webapp + uses: azure/webapps-deploy@v2 + with: + app-name: 'gdbmvc' + slot-name: 'Production' + package: . diff --git a/db/scripts/initial_data/3_InitialData-0001-Audit.sql b/db/scripts/initial_data/3_InitialData-0001-Audit.sql new file mode 100644 index 000000000..b16be7c0d --- /dev/null +++ b/db/scripts/initial_data/3_InitialData-0001-Audit.sql @@ -0,0 +1,13 @@ +-- Add audit data for the Company table +INSERT INTO [dbo].[AuditableEntity] ([EntityName], [EnableAudit]) VALUES ('Company', 1); + +DECLARE @auditableEntityId INT; +SELECT @auditableEntityId = [Id] FROM [dbo].[AuditableEntity] WHERE [EntityName] = 'Company'; + +-- Add attributes for the Company table +INSERT INTO [dbo].[AuditableAttribute] ([AuditableEntityId], [AttributeName], [EnableAudit]) +VALUES + (@auditableEntityId, 'CompanyCode', 1), + (@auditableEntityId, 'Name', 1), + (@auditableEntityId, 'ShortName', 1), + (@auditableEntityId, 'CRA', 1); \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index c7fef8216..8901497e3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,5 @@ version: "3" -services: +services: api: image: accountgo/accountgoapi build: @@ -8,14 +8,7 @@ services: ports: - "8001:8001" environment: - # - ASPNETCORE_ENVIRONMENT=Production - ASPNETCORE_URLS=http://+:8001 - # - DBSERVER=localhost - # - DBUSERID=dbuser - # - DBPASSWORD=Str0ngPassword - # - DBNAME=accountgodb - # depends_on: - # - db web: image: accountgo/accountgoweb build: @@ -24,13 +17,5 @@ services: ports: - "8000:8000" environment: - # - ASPNETCORE_ENVIRONMENT=Production - ASPNETCORE_URLS=http://+:8000 - APIHOST=api - # db: - # image: microsoft/mssql-server-linux - # ports: - # - "1433:1433" - # environment: - # SA_PASSWORD: "Str0ngPassword" - # ACCEPT_EULA: "Y" \ No newline at end of file diff --git a/docs/Bootstrap Blazor.txt b/docs/Bootstrap Blazor.txt new file mode 100644 index 000000000..97341be99 --- /dev/null +++ b/docs/Bootstrap Blazor.txt @@ -0,0 +1,93 @@ +https://github.com/vikramlearning/blazorbootstrap-starter-templates/tree/master + + +dotnet add package Blazor.Bootstrap -v 3.0.0-preview.2 + +Program.cs + + builder.Services.AddBlazorBootstrap(); // Add this line + +_Imports.razor + + @using BlazorBootstrap; + +Delete wwwroot/bootstrap folder + +Replace MainLayout.razor with: + + @inherits LayoutComponentBase + +
+ + + +
+
+ About +
+ +
+
@Body
+
+
+ +
+ + @code { + Sidebar sidebar; + IEnumerable navItems; + + private async Task SidebarDataProvider(SidebarDataProviderRequest request) + { + if (navItems is null) + navItems = GetNavItems(); + + return await Task.FromResult(request.ApplyTo(navItems)); + } + + private IEnumerable GetNavItems() + { + navItems = new List + { + new NavItem { Id = "1", Href = "/", IconName = IconName.HouseDoorFill, Text = "Home", Match=NavLinkMatch.All}, + new NavItem { Id = "2", Href = "/counter", IconName = IconName.PlusSquareFill, Text = "Counter"}, + new NavItem { Id = "3", Href = "/weather", IconName = IconName.Table, Text = "Fetch Data"}, + }; + + return navItems; + } + } + + +
+ An unhandled error has occurred. + Reload + 🗙 +
+ +App.razor + + 1) Delete >> + 2) Add these lines at top of file under + + + + + + 3) Add these lines at bottom of file under + + + + + + + + + 4) Change to: + + + + \ No newline at end of file diff --git a/docs/GoodDeedBooks.docx b/docs/GoodDeedBooks.docx new file mode 100644 index 000000000..30ae3bee2 Binary files /dev/null and b/docs/GoodDeedBooks.docx differ diff --git a/docs/README.md b/docs/README.md index 74552fce9..c4965d29f 100644 --- a/docs/README.md +++ b/docs/README.md @@ -128,7 +128,7 @@ At this point, your database has no data on it. But there is already an initial - Items - Banks -To initialize a company, call the api endpoint directly http://localhost:8001/api/administration/initializedcompany from the browser or by using curl e.g. `curl http://localhost:8001/api/administration/initializedcompany`. If you encounter some issues, the easy way for now is recreate your database and repeat the `Publish Database` section. +To initialize a company, call the api endpoint directly http://localhost:8001/api/administration/setup from the browser or by using curl e.g. `curl http://localhost:8001/api/administration/setup`. If you encounter some issues, the easy way for now is recreate your database and repeat the `Publish Database` section. ## Build and Run "Api" (Back-end) 1. Navigate directory to `src/Api` project @@ -181,7 +181,7 @@ To run everything (database, api, web) in docker container you can use docker-co 1. Database instance running in docker container and you can connect to it 1. You should have a running "Api" and can test it by getting the list of customers e.g. http://localhost:8001/api/sales customers 1. You can browse the UI from http://localhost:8000 and able to login to the system using initial username/password: admin@accountgo.ph/P@ssword1 -1. Initialize data by calling a special api endpoint directly. http://localhost:8001/api/administration/initializedcompany +1. Initialize data by calling a special api endpoint directly: http://localhost:8001/api/administration/setup # Technology Stack - ASP.NET Core 3.1 @@ -207,4 +207,4 @@ If you are a developer and wanted to take part as contributor/collaborator we ar So go ahead, add your code and make your first pull request. # Contact Support -Feel free to email mvpsolution@gmail.com of any questions. \ No newline at end of file +Feel free to email mvpsolution@gmail.com of any questions. diff --git a/docs/azure.txt b/docs/azure.txt new file mode 100644 index 000000000..1e437cd3d --- /dev/null +++ b/docs/azure.txt @@ -0,0 +1,8 @@ +API: +https://goodbooksapi.azurewebsites.net + +MVC: +https://good-books.azurewebsites.net + +React: +https://mango-glacier-0edfec41e.5.azurestaticapps.net diff --git a/docs/background.txt b/docs/background.txt new file mode 100644 index 000000000..dfd5d92f3 --- /dev/null +++ b/docs/background.txt @@ -0,0 +1,41 @@ +I was asked by a non-profit organization to help them find a cheap accounting system instead of paying high subscription fees from a current vendor. I stumbled upon this open source project on GitHub: + +https://github.com/AccountGo/accountgo + +It is based on the following technologies: + +Backend: ASP.NET WebAPI and MVC +Frontend: React with TypeScript +Database: SQL Server + +It seems that development on this app stopped about seven years ago. When I looked at it, I figured that it has most of what is needed and could be brought up to snuff by upgrading the application to the latest state of .NET and React. Therefore, I forked it and updated it to the latest versions of .NET, React, and TypeScript. + +The forked app is at https://github.com/medhatelmasry/GoodBooks + +You can run it by following these steps: + +Clone the repo +Start SQL Server in a docker container with: + + docker run --cap-add SYS_PTRACE -e ACCEPT_EULA=1 -e MSSQL_SA_PASSWORD=SqlPassword! -p 1444:1433 --name azsql -d mcr.microsoft.com/azure-sql-edge + +In root directory of the code, run the following commands: + + dotnet ef migrations add M1 --project ./src/Api/ --startup-project ./src/Api/Api.csproj --msbuildprojectextensionspath .build/obj/Api/ --context ApplicationIdentityDbContext --output-dir Data/Migrations/IdentityDb + + dotnet ef migrations add M2 --project ./src/Api/ --startup-project ./src/Api/Api.csproj --msbuildprojectextensionspath .build/obj/Api/ --context ApiDbContext --output-dir Data/Migrations/ApiDb + + dotnet ef database update --project ./src/Api/ --msbuildprojectextensionspath .build/obj/Api/ --context ApplicationIdentityDbContext + + dotnet ef database update --project ./src/Api/ --msbuildprojectextensionspath .build/obj/Api/ --context ApiDbContext + +Update to the latest versions of Node & Npm +Go to the src/Api folder and start the WebAPI app with: dotnet watch +Hit this endpoint in order to populate the database with some sample data: http://localhost:8001/api/administration/setup +In a separate terminal window, go to the src/GoodBooksReact folder run these commands: + + npm install + npm run dev + +The React app will run. It is a rudimentary frontend menu system and is a work in progress. + diff --git a/docs/expand-chart-of-accounts.docx b/docs/expand-chart-of-accounts.docx new file mode 100644 index 000000000..0ebf39cf4 Binary files /dev/null and b/docs/expand-chart-of-accounts.docx differ diff --git a/docs/medhat.txt b/docs/medhat.txt new file mode 100644 index 000000000..b66e10c56 --- /dev/null +++ b/docs/medhat.txt @@ -0,0 +1,28 @@ +docker run --cap-add SYS_PTRACE -e ACCEPT_EULA=1 -e MSSQL_SA_PASSWORD=SqlPassword! -p 1444:1433 --name azsql -d mcr.microsoft.com/azure-sql-edge + +Data Source=localhost,1444;Database=Northwind;Persist Security Info=True;User ID=sa;Password=SqlPassword!;TrustServerCertificate=True; + +==================== + +dotnet ef migrations add M1 --project ./src/Api/ --startup-project ./src/Api/Api.csproj --msbuildprojectextensionspath .build/obj/Api/ --context ApplicationIdentityDbContext --output-dir Data/Migrations/IdentityDb + +dotnet ef migrations add M2 --project ./src/Api/ --startup-project ./src/Api/Api.csproj --msbuildprojectextensionspath .build/obj/Api/ --context ApiDbContext --output-dir Data/Migrations/ApiDb + +==================== + +dotnet ef database update --project ./src/Api/ --msbuildprojectextensionspath .build/obj/Api/ --context ApplicationIdentityDbContext + +dotnet ef database update --project ./src/Api/ --msbuildprojectextensionspath .build/obj/Api/ --context ApiDbContext + +==================== + +Update to the latest versions of node & npm + +==================== + +Start the API .NET application then hit this endpoint in a browser to create seed data: +http://localhost:8001/api/administration/setup + + + + diff --git a/docs/open-source.txt b/docs/open-source.txt new file mode 100644 index 000000000..38db29dbc --- /dev/null +++ b/docs/open-source.txt @@ -0,0 +1,3 @@ +Open Source Accounting System + +https://github.com/AccountGo/accountgo diff --git a/docs/pr.txt b/docs/pr.txt new file mode 100644 index 000000000..b5b7b5215 --- /dev/null +++ b/docs/pr.txt @@ -0,0 +1,19 @@ +git checkout -b dotnet_9 origin/dotnet_9 + +docker run --cap-add SYS_PTRACE -e ACCEPT_EULA=1 -e MSSQL_SA_PASSWORD=SqlPassword! -p 1444:1433 --name sql -d mcr.microsoft.com/mssql/server:2022-latest + +--------- + +dotnet ef migrations add M1 --project ./src/Api/ --startup-project ./src/Api/Api.csproj --msbuildprojectextensionspath .build/obj/Api/ --context ApplicationIdentityDbContext --output-dir Data/Migrations/IdentityDb + +dotnet ef migrations add M2 --project ./src/Api/ --startup-project ./src/Api/Api.csproj --msbuildprojectextensionspath .build/obj/Api/ --context ApiDbContext --output-dir Data/Migrations/ApiDb + +dotnet ef database update --project ./src/Api/ --msbuildprojectextensionspath .build/obj/Api/ --context ApplicationIdentityDbContext + +dotnet ef database update --project ./src/Api/ --msbuildprojectextensionspath .build/obj/Api/ --context ApiDbContext + +========== + +Apply Entity Framework Core migrations in .NET Aspire + https://learn.microsoft.com/en-us/dotnet/aspire/database/ef-core-migrations + diff --git a/docs/react.txt b/docs/react.txt new file mode 100644 index 000000000..2e56c21d6 --- /dev/null +++ b/docs/react.txt @@ -0,0 +1,4 @@ +https://www.youtube.com/watch?v=ElgfQdq-Htk + +https://www.youtube.com/watch?v=oN9W0Tkn8hg + diff --git a/move-to-blazor.txt b/move-to-blazor.txt new file mode 100644 index 000000000..e388316b6 --- /dev/null +++ b/move-to-blazor.txt @@ -0,0 +1,9 @@ +Recreate starter Blazor app with database authentication +- we will use JWT for client-side authentication + +Get chart of account to work + +CI/CD GiHul >> Azure + +Meet and decide on moving the current application into the Blazor template + diff --git a/src/AccountGoWeb/.vscode/launch.json b/src/AccountGoWeb/.vscode/launch.json index 5825c3616..ddd8758f9 100644 --- a/src/AccountGoWeb/.vscode/launch.json +++ b/src/AccountGoWeb/.vscode/launch.json @@ -4,6 +4,11 @@ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ + { + "name": ".NET Core Attach", + "type": "coreclr", + "request": "attach" + }, { "name": ".NET Core Launch (web)", "type": "coreclr", diff --git a/src/AccountGoWeb/AccountGoWeb.csproj b/src/AccountGoWeb/AccountGoWeb.csproj index 0175223c6..cea3034a4 100644 --- a/src/AccountGoWeb/AccountGoWeb.csproj +++ b/src/AccountGoWeb/AccountGoWeb.csproj @@ -1,46 +1,34 @@ - - + - net7.0 - true - AccountGoWeb - AccountGoWeb - latest - 0.0.1-alpha - Latest + net9.0 + GoodBooks + GoodBooks + 1.0.0 + enable + enable + true + aspnet-GoodBooks-21ac3a7f-d42e-4136-9340-b4f6254706df + NU1701 - PreserveNewest - + + - + - - + + + + - - - - - - - - - - - - - - - - - + + \ No newline at end of file diff --git a/src/AccountGoWeb/Components/App.razor b/src/AccountGoWeb/Components/App.razor new file mode 100644 index 000000000..a99d041ea --- /dev/null +++ b/src/AccountGoWeb/Components/App.razor @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/AccountGoWeb/Components/Pages/Counter.razor b/src/AccountGoWeb/Components/Pages/Counter.razor new file mode 100644 index 000000000..0d9d43ad4 --- /dev/null +++ b/src/AccountGoWeb/Components/Pages/Counter.razor @@ -0,0 +1,19 @@ +@page "/counter" +@rendermode InteractiveServer + +Counter + +

Counter

+ +

Current count: @currentCount

+ + + +@code { + private int currentCount = 0; + + private void IncrementCount() + { + currentCount++; + } +} diff --git a/src/AccountGoWeb/Components/Pages/Financial/ChartOfAccounts.razor b/src/AccountGoWeb/Components/Pages/Financial/ChartOfAccounts.razor new file mode 100644 index 000000000..21557a326 --- /dev/null +++ b/src/AccountGoWeb/Components/Pages/Financial/ChartOfAccounts.razor @@ -0,0 +1,369 @@ +@page "/financials/chart-of-accounts" +@using System.Text.Json +@using System.Text.Json.Serialization +@using LibraryGDB.Models.Financial +@using Microsoft.JSInterop +@using Microsoft.Net.Http.Headers +@inject IHttpClientFactory ClientFactory +@inject Microsoft.JSInterop.IJSRuntime JSRuntime + +Chart of Accounts + +

Chart Of Accounts

+ +@if (getError || accounts is null) +{ +
Unable to get data. Please try again later.
+} +else if (isLoading) +{ +

Loading accounts...

+} +else +{ + @*
    + @foreach (var item in accounts) + { +
  • @item.AccountName
  • + } +
*@ + +
+ + + + + + + + + + + + + + + @for (int accountIdx = 0; accountIdx < accounts.Count(); ++accountIdx) + { + var account = accounts.ToList()[accountIdx]; + var accountTargetId = $"asset-{accountIdx}"; + + + + + + + + + + + + + + } + +
CodeNameBalanceDebitCreditActions
+ +
+
+ +} +@if (isAddModalVisible || isEditModalVisible) +{ + +} + +@if (isDeleteModalVisible) +{ + +} + +@code { + private List accounts = new(); + private AccountViewModel? selectedAccount = null; + private bool isAddModalVisible = false; + private bool isEditModalVisible = false; + private bool isDeleteModalVisible = false; + private string errorMessage = string.Empty; + private bool isLoading = true; + private bool getError = false; + + // Fetch accounts from API on initialization + protected override async Task OnInitializedAsync() + { + await LoadAccountsFromApi(); + isLoading = false; + } + + // Load accounts from API + private async Task LoadAccountsFromApi() + { + try + { + string apiUrl = Environment.GetEnvironmentVariable("APIURL") ?? "http://localhost:8001/api/"; + var client = ClientFactory.CreateClient(); + + var response = await client.GetAsync($"{apiUrl}financials/accounts"); + + if (response.IsSuccessStatusCode) + { + var jsonString = await response.Content.ReadAsStringAsync(); + accounts = JsonSerializer.Deserialize>(jsonString, new JsonSerializerOptions + { + PropertyNameCaseInsensitive = true + }) ?? new List(); + } + else + { + getError = true; + } + } + catch + { + getError = true; + } + } + + + // Open Add Modal + private void OpenAddModal() + { + selectedAccount = new AccountViewModel(); + errorMessage = string.Empty; + isAddModalVisible = true; + } + + // Open Edit Modal + private void OpenEditModal(AccountViewModel account) + { + selectedAccount = new AccountViewModel + { + AccountCode = account.AccountCode, + AccountName = account.AccountName, + TotalBalance = account.TotalBalance, + TotalDebitBalance = account.TotalDebitBalance, + TotalCreditBalance = account.TotalCreditBalance, + ChildAccounts = account.ChildAccounts + }; + errorMessage = string.Empty; + isEditModalVisible = true; + } + + // Close Add or Edit Modal + private void CloseModal() + { + isAddModalVisible = false; + isEditModalVisible = false; + selectedAccount = null; + } + + // Open Delete Modal + private void OpenDeleteModal(AccountViewModel account) + { + selectedAccount = account; + isDeleteModalVisible = true; + } + + // Close Delete Modal + private void CloseDeleteModal() + { + isDeleteModalVisible = false; + selectedAccount = null; + } + + // Add or Update Account + private void SaveAccount() + { + if (selectedAccount == null) + { + errorMessage = "No account selected."; + return; + } + + if (string.IsNullOrWhiteSpace(selectedAccount.AccountCode) || string.IsNullOrWhiteSpace(selectedAccount.AccountName)) + { + errorMessage = "Both Account Code and Account Name are required."; + return; + } + + if (isEditModalVisible) + { + // Edit existing account locally + var account = accounts.FirstOrDefault(a => a.AccountCode == selectedAccount.AccountCode); + if (account != null) + { + account.AccountName = selectedAccount.AccountName; + account.TotalBalance = selectedAccount.TotalBalance; + account.TotalDebitBalance = selectedAccount.TotalDebitBalance; + account.TotalCreditBalance = selectedAccount.TotalCreditBalance; + } + else + { + errorMessage = "Account not found."; + } + } + else + { + // Add new account locally + if (accounts.Any(a => a.AccountCode == selectedAccount.AccountCode)) + { + errorMessage = "An account with this Account Code already exists."; + return; + } + + accounts.Add(new AccountViewModel + { + AccountCode = selectedAccount.AccountCode, + AccountName = selectedAccount.AccountName, + TotalBalance = selectedAccount.TotalBalance, + TotalDebitBalance = selectedAccount.TotalDebitBalance, + TotalCreditBalance = selectedAccount.TotalCreditBalance, + ChildAccounts = new List() + }); + } + + CloseModal(); + } + + // Delete Account + private void ConfirmDeleteAccount() + { + if (selectedAccount == null) + { + errorMessage = "No account selected."; + return; + } + + accounts.Remove(selectedAccount); + CloseDeleteModal(); + } + + // ViewModel for Accounts + public class AccountViewModel + { + public string AccountCode { get; set; } = string.Empty; + public string AccountName { get; set; } = string.Empty; + public decimal TotalBalance { get; set; } + public decimal TotalDebitBalance { get; set; } + public decimal TotalCreditBalance { get; set; } + public List ChildAccounts { get; set; } = new(); + } +} diff --git a/src/AccountGoWeb/Components/Pages/Students.razor b/src/AccountGoWeb/Components/Pages/Students.razor new file mode 100644 index 000000000..443d791b0 --- /dev/null +++ b/src/AccountGoWeb/Components/Pages/Students.razor @@ -0,0 +1,23 @@ +@page "/students" +@rendermode InteractiveServer +Students +

Students

+ + + +
+ + @context.FirstName @context.LastName + +
+
+ +
+ + +@code { + IQueryable students = Student.GetStudents(); + PaginationState pagination = new PaginationState { ItemsPerPage = 10 }; + GridSort sortByName = GridSort + .ByAscending(_ => _.FirstName).ThenAscending(_ => _.LastName); +} \ No newline at end of file diff --git a/src/AccountGoWeb/Components/Routes.razor b/src/AccountGoWeb/Components/Routes.razor new file mode 100644 index 000000000..da8815572 --- /dev/null +++ b/src/AccountGoWeb/Components/Routes.razor @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/AccountGoWeb/Components/_Imports.razor b/src/AccountGoWeb/Components/_Imports.razor new file mode 100644 index 000000000..8eccd6b2e --- /dev/null +++ b/src/AccountGoWeb/Components/_Imports.razor @@ -0,0 +1,18 @@ +@using System.Net.Http +@using System.Net.Http.Json +@using Microsoft.AspNetCore.Components.Forms +@using Microsoft.AspNetCore.Components.Routing +@using Microsoft.AspNetCore.Components.Web +@using static Microsoft.AspNetCore.Components.Web.RenderMode +@using Microsoft.AspNetCore.Components.Web.Virtualization +@using Microsoft.JSInterop +@using Microsoft.AspNetCore.Components.QuickGrid +@using AccountGoWeb +@using AccountGoWeb.Components +@using AccountGoWeb.Models +@using AccountGoWeb.Models.Account +@using AccountGoWeb.Models.Bogus +@using AccountGoWeb.Models.Financial +@using AccountGoWeb.Models.Purchasing +@using AccountGoWeb.Models.Sales +@using AccountGoWeb.Models.TaxSystem diff --git a/src/AccountGoWeb/Controllers/AccountController.cs b/src/AccountGoWeb/Controllers/AccountController.cs index 0eba93c37..9d558d04e 100644 --- a/src/AccountGoWeb/Controllers/AccountController.cs +++ b/src/AccountGoWeb/Controllers/AccountController.cs @@ -3,25 +3,20 @@ using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Configuration; -using System; -using System.Collections.Generic; -using System.Net.Http; using System.Security.Claims; -using System.Threading.Tasks; namespace AccountGoWeb.Controllers { - public class AccountController : BaseController + public class AccountController : GoodController { public AccountController(IConfiguration config) { - _baseConfig = config; + _configuration = config; } [HttpGet] [AllowAnonymous] - public IActionResult SignIn(string returnUrl = null) + public IActionResult SignIn(string? returnUrl = null) { ViewData["ReturnUrl"] = returnUrl; return View(new LoginViewModel() { Email = "admin@accountgo.ph", Password = "P@ssword1" }); @@ -29,7 +24,7 @@ public IActionResult SignIn(string returnUrl = null) [HttpPost] [AllowAnonymous] - public async Task SignIn(LoginViewModel model, string returnUrl = null) + public async Task SignIn(LoginViewModel model, string? returnUrl = null) { ViewData["ReturnUrl"] = returnUrl; @@ -47,8 +42,8 @@ public async Task SignIn(LoginViewModel model, string returnUrl = var claims = new List(); claims.Add(new Claim(ClaimTypes.IsPersistent, model.RememberMe.ToString())); - claims.Add(new Claim(ClaimTypes.NameIdentifier, user.Email)); - claims.Add(new Claim(ClaimTypes.Email, user.Email)); + claims.Add(new Claim(ClaimTypes.NameIdentifier, user.Email!)); + claims.Add(new Claim(ClaimTypes.Email, user.Email!)); string firstName = user.FirstName != null ? user.FirstName : ""; string lastName = user.LastName != null ? user.LastName : ""; @@ -58,7 +53,7 @@ public async Task SignIn(LoginViewModel model, string returnUrl = claims.Add(new Claim(ClaimTypes.Name, firstName + " " + lastName)); foreach(var role in user.Roles) - claims.Add(new Claim(ClaimTypes.Role, role.Name)); + claims.Add(new Claim(ClaimTypes.Role, role.Name!)); claims.Add(new Claim(ClaimTypes.UserData, Newtonsoft.Json.JsonConvert.SerializeObject(user))); @@ -70,7 +65,7 @@ public async Task SignIn(LoginViewModel model, string returnUrl = await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal); - return RedirectToLocal(returnUrl); + return RedirectToLocal(returnUrl!); } else { @@ -92,7 +87,7 @@ public async Task SignOut() public IActionResult SignedOut() { - if (HttpContext.User.Identity.IsAuthenticated) + if (HttpContext.User.Identity!.IsAuthenticated) { return RedirectToAction(nameof(HomeController.Index), "Home"); } @@ -106,7 +101,7 @@ public IActionResult Unauthorize() [HttpGet] [AllowAnonymous] - public IActionResult Register(string returnUrl = null) + public IActionResult Register(string? returnUrl = null) { ViewData["ReturnUrl"] = returnUrl; return View(); @@ -114,7 +109,7 @@ public IActionResult Register(string returnUrl = null) [HttpPost] [AllowAnonymous] - public IActionResult Register(RegisterViewModel model, string returnUrl = null) + public IActionResult Register(RegisterViewModel model, string? returnUrl = null) { ViewData["ReturnUrl"] = returnUrl; try @@ -127,9 +122,9 @@ public IActionResult Register(RegisterViewModel model, string returnUrl = null) HttpResponseMessage responseAddNewUser = Post("account/addnewuser", content); Newtonsoft.Json.Linq.JObject resultAddNewUser = Newtonsoft.Json.Linq.JObject.Parse(responseAddNewUser.Content.ReadAsStringAsync().Result); - HttpResponseMessage responseInitialized = null; - Newtonsoft.Json.Linq.JObject resultInitialized = null; - if ((bool)resultAddNewUser["succeeded"]) + HttpResponseMessage? responseInitialized = null; + Newtonsoft.Json.Linq.JObject? resultInitialized = null; + if ((bool)resultAddNewUser["succeeded"]!) { responseInitialized = Get("administration/initializedcompany"); resultInitialized = Newtonsoft.Json.Linq.JObject.Parse((responseInitialized.Content.ReadAsStringAsync().Result)); @@ -137,7 +132,7 @@ public IActionResult Register(RegisterViewModel model, string returnUrl = null) } else { - ModelState.AddModelError(string.Empty, resultAddNewUser["errors"][0]["description"].ToString()); + ModelState.AddModelError(string.Empty, resultAddNewUser["errors"]![0]!["description"]!.ToString()); return View(model); } } diff --git a/src/AccountGoWeb/Controllers/AdministrationController.cs b/src/AccountGoWeb/Controllers/AdministrationController.cs index a05f3f301..148b81334 100644 --- a/src/AccountGoWeb/Controllers/AdministrationController.cs +++ b/src/AccountGoWeb/Controllers/AdministrationController.cs @@ -1,14 +1,11 @@ using Dto.Administration; using Dto.Security; using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Configuration; -using System; -using System.Net.Http; namespace AccountGoWeb.Controllers { - [Microsoft.AspNetCore.Authorization.Authorize] - public class AdministrationController : BaseController + //[Microsoft.AspNetCore.Authorization.Authorize] + public class AdministrationController : BaseController { public AdministrationController(IConfiguration config) { @@ -125,13 +122,13 @@ public async System.Threading.Tasks.Task AuditLogs() HttpResponseMessage responseAddNewUser = Post("account/addnewuser", content); Newtonsoft.Json.Linq.JObject resultAddNewUser = Newtonsoft.Json.Linq.JObject.Parse(responseAddNewUser.Content.ReadAsStringAsync().Result); - if ((bool)resultAddNewUser["succeeded"]) + if ((bool)resultAddNewUser["succeeded"]!) { return RedirectToAction(nameof(AdministrationController.Users), "Administration"); } else { - ModelState.AddModelError(string.Empty, resultAddNewUser["errors"][0]["description"].ToString()); + ModelState.AddModelError(string.Empty, resultAddNewUser["errors"]![0]!["description"]!.ToString()); return View(model); } } diff --git a/src/AccountGoWeb/Controllers/BaseController.cs b/src/AccountGoWeb/Controllers/BaseController.cs index aafb66c5b..8a4193f01 100644 --- a/src/AccountGoWeb/Controllers/BaseController.cs +++ b/src/AccountGoWeb/Controllers/BaseController.cs @@ -1,20 +1,18 @@ using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Configuration; -using System.Net.Http; namespace AccountGoWeb.Controllers { public class BaseController : Controller { - protected IConfiguration _baseConfig; + protected IConfiguration? _baseConfig; protected async System.Threading.Tasks.Task GetAsync(string uri) { string responseJson = string.Empty; using (var client = new HttpClient()) { - var baseUri = _baseConfig["ApiUrl"]; - client.BaseAddress = new System.Uri(baseUri); + var baseUri = _baseConfig!["ApiUrl"]; + client.BaseAddress = new System.Uri(baseUri!); client.DefaultRequestHeaders.Accept.Clear(); var response = await client.GetAsync(baseUri + uri); if (response.IsSuccessStatusCode) @@ -22,7 +20,7 @@ protected async System.Threading.Tasks.Task GetAsync(string uri) responseJson = await response.Content.ReadAsStringAsync(); } } - return Newtonsoft.Json.JsonConvert.DeserializeObject(responseJson); + return Newtonsoft.Json.JsonConvert.DeserializeObject(responseJson)!; } protected HttpResponseMessage Get(string uri) @@ -30,8 +28,8 @@ protected HttpResponseMessage Get(string uri) string responseJson = string.Empty; using (var client = new HttpClient()) { - var baseUri = _baseConfig["ApiUrl"]; - client.BaseAddress = new System.Uri(baseUri); + var baseUri = _baseConfig!["ApiUrl"]; + client.BaseAddress = new System.Uri(baseUri!); client.DefaultRequestHeaders.Accept.Clear(); var response = client.GetAsync(baseUri + uri); return response.Result; @@ -43,8 +41,8 @@ protected async System.Threading.Tasks.Task PostAsync(string uri, String string responseJson = string.Empty; using (var client = new HttpClient()) { - var baseUri = _baseConfig["ApiUrl"]; - client.BaseAddress = new System.Uri(baseUri); + var baseUri = _baseConfig!["ApiUrl"]; + client.BaseAddress = new System.Uri(baseUri!); client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Add("UserName", GetCurrentUserName()); @@ -55,7 +53,7 @@ protected async System.Threading.Tasks.Task PostAsync(string uri, String } } - return Newtonsoft.Json.JsonConvert.DeserializeObject(responseJson); + return Newtonsoft.Json.JsonConvert.DeserializeObject(responseJson)!; } protected HttpResponseMessage Post(string uri, StringContent data) @@ -63,8 +61,8 @@ protected HttpResponseMessage Post(string uri, StringContent data) string responseJson = string.Empty; using (var client = new HttpClient()) { - var baseUri = _baseConfig["ApiUrl"]; - client.BaseAddress = new System.Uri(baseUri); + var baseUri = _baseConfig!["ApiUrl"]; + client.BaseAddress = new System.Uri(baseUri!); client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json")); client.DefaultRequestHeaders.Add("UserName", GetCurrentUserName()); @@ -76,7 +74,7 @@ protected HttpResponseMessage Post(string uri, StringContent data) protected bool HasPermission(string permission) { - if (HttpContext.User.Identity.IsAuthenticated) + if (HttpContext.User.Identity!.IsAuthenticated) { System.Collections.Generic.IList permissions = new System.Collections.Generic.List(); @@ -87,11 +85,11 @@ protected bool HasPermission(string permission) if (current.Type == System.Security.Claims.ClaimTypes.UserData) { Newtonsoft.Json.Linq.JObject userData = Newtonsoft.Json.Linq.JObject.Parse(current.Value); - foreach(var r in userData["Roles"]) + foreach(var r in userData["Roles"]!) { - foreach(var p in r["Permissions"]) + foreach(var p in r["Permissions"]!) { - permissions.Add(p["Name"].ToString()); + permissions.Add(p["Name"]!.ToString()); } } } @@ -105,7 +103,7 @@ protected bool HasPermission(string permission) protected string GetCurrentUserName() { - if (HttpContext.User.Identity.IsAuthenticated) + if (HttpContext.User.Identity!.IsAuthenticated) { var claimsEnumerator = HttpContext.User.Claims.GetEnumerator(); while (claimsEnumerator.MoveNext()) diff --git a/src/AccountGoWeb/Controllers/ContactController.cs b/src/AccountGoWeb/Controllers/ContactController.cs index fd3e1a60a..f22788253 100644 --- a/src/AccountGoWeb/Controllers/ContactController.cs +++ b/src/AccountGoWeb/Controllers/ContactController.cs @@ -1,11 +1,5 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; +using Dto.Common; using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Configuration; -using System.Net.Http; -using Dto.Common; // For more information on enabling MVC for empty projects, visit http://go.microsoft.com/fwlink/?LinkID=397860 namespace AccountGoWeb.Controllers @@ -35,8 +29,8 @@ public async System.Threading.Tasks.Task Contacts(int partyId = 0 //return View(model: contacts); using (var client = new HttpClient()) { - var baseUri = _baseConfig["ApiUrl"]; - client.BaseAddress = new System.Uri(baseUri); + var baseUri = _baseConfig!["ApiUrl"]; + client.BaseAddress = new System.Uri(baseUri!); client.DefaultRequestHeaders.Accept.Clear(); var response = await client.GetAsync(baseUri + "contact/contacts?partyId=" + partyId + "&partyType=" + partyType); if (response.IsSuccessStatusCode) @@ -57,7 +51,7 @@ public async System.Threading.Tasks.Task Contacts(int partyId = 0 /// public IActionResult Contact(int id = 0, int partyId = 0, int partyType = 0) { - Contact contact = null; + Contact? contact = null; if (id == 0) // creating new contact { diff --git a/src/AccountGoWeb/Controllers/DashboardController.cs b/src/AccountGoWeb/Controllers/DashboardController.cs index c8791445a..0753e5208 100644 --- a/src/AccountGoWeb/Controllers/DashboardController.cs +++ b/src/AccountGoWeb/Controllers/DashboardController.cs @@ -1,9 +1,8 @@ using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Configuration; namespace AccountGoWeb.Controllers { - [Microsoft.AspNetCore.Authorization.Authorize] + //[Microsoft.AspNetCore.Authorization.Authorize] public class DashboardController : BaseController { public DashboardController(IConfiguration config) @@ -19,7 +18,7 @@ public IActionResult Index() public IActionResult MonthlySales() { - ViewBag.ApiMontlySales = _baseConfig["ApiUrl"] + "sales/getmonthlysales"; + ViewBag.ApiMontlySales = _baseConfig!["ApiUrl"] + "sales/getmonthlysales"; return View(); } } diff --git a/src/AccountGoWeb/Controllers/FinancialsController.cs b/src/AccountGoWeb/Controllers/FinancialsController.cs index bbe60f680..f33c1b61f 100644 --- a/src/AccountGoWeb/Controllers/FinancialsController.cs +++ b/src/AccountGoWeb/Controllers/FinancialsController.cs @@ -1,196 +1,215 @@ using Microsoft.AspNetCore.Mvc; -using System.Collections.Generic; namespace AccountGoWeb.Controllers { - [Microsoft.AspNetCore.Authorization.Authorize] - public class FinancialsController : BaseController + //[Microsoft.AspNetCore.Authorization.Authorize] + public class FinancialsController : BaseController + { + private readonly ILogger _logger; + + public FinancialsController(IConfiguration config, ILogger logger) { - public FinancialsController(Microsoft.Extensions.Configuration.IConfiguration config) - { - _baseConfig = config; - } + _baseConfig = config; + _logger = logger; + } - public IActionResult AddJournalEntry() - { - ViewBag.PageContentHeader = "Add Journal Entry"; - return View(); - } + public IActionResult AddJournalEntry() + { + ViewBag.PageContentHeader = "Add Journal Entry"; + return View(); + } - public IActionResult JournalEntry(int id) - { - ViewBag.PageContentHeader = "Journal Entry"; - return View(); - } + public IActionResult JournalEntry(int id) + { + ViewBag.PageContentHeader = "Journal Entry"; + return View(); + } - public async System.Threading.Tasks.Task Accounts() + public async Task Accounts() + { + ViewBag.PageContentHeader = "Chart of Accounts"; + + using (var client = new System.Net.Http.HttpClient()) + { + var baseUri = _baseConfig!["ApiUrl"]; + _logger.LogInformation($"+++++++++++++++ baseUri={baseUri} +++++++++++++++"); + client.BaseAddress = new System.Uri(baseUri!); + client.DefaultRequestHeaders.Accept.Clear(); + var response = await client.GetAsync(baseUri + "financials/accounts"); + if (response.IsSuccessStatusCode) { - ViewBag.PageContentHeader = "Accounts"; - - using (var client = new System.Net.Http.HttpClient()) - { - var baseUri = _baseConfig["ApiUrl"]; - client.BaseAddress = new System.Uri(baseUri); - client.DefaultRequestHeaders.Accept.Clear(); - var response = await client.GetAsync(baseUri + "financials/accounts"); - if (response.IsSuccessStatusCode) - { - var responseJson = await response.Content.ReadAsStringAsync(); - return View(model: responseJson); - } - } - - return View(); + var responseJson = await response.Content.ReadAsStringAsync(); + var accountModels = Newtonsoft.Json.JsonConvert.DeserializeObject>(responseJson); + return View(accountModels); } + } + + return View(); + } + + public async Task Account(int? id = null) + { + Dto.Financial.Account? accountModel = null; + if (id == null) + { + accountModel = new Dto.Financial.Account(); + } + else + { + accountModel = await GetAsync("financials/account?id=" + id); + } + + ViewBag.PageContentHeader = "Account"; + return View(accountModel); + } - public async System.Threading.Tasks.Task Account(int? id = null) + public async System.Threading.Tasks.Task JournalEntries() + { + ViewBag.PageContentHeader = "Journal Entries"; + + using (var client = new System.Net.Http.HttpClient()) + { + var baseUri = _baseConfig!["ApiUrl"]; + client.BaseAddress = new System.Uri(baseUri!); + client.DefaultRequestHeaders.Accept.Clear(); + var response = await client.GetAsync(baseUri + "financials/journalentries"); + if (response.IsSuccessStatusCode) { - Dto.Financial.Account accountModel = null; - if (id == null) - { - accountModel = new Dto.Financial.Account(); - } - else - { - accountModel = await GetAsync("financials/account?id=" + id); - } - - ViewBag.PageContentHeader = "Account"; - return View(accountModel); + var responseJson = await response.Content.ReadAsStringAsync(); + return View(model: responseJson); } + } + + return View(); + } - public async System.Threading.Tasks.Task JournalEntries() + public async System.Threading.Tasks.Task GeneralLedger() + { + ViewBag.PageContentHeader = "General Ledger"; + + using (var client = new System.Net.Http.HttpClient()) + { + var baseUri = _baseConfig!["ApiUrl"]; + client.BaseAddress = new System.Uri(baseUri!); + client.DefaultRequestHeaders.Accept.Clear(); + var response = await client.GetAsync(baseUri + "financials/generalledger"); + if (response.IsSuccessStatusCode) { - ViewBag.PageContentHeader = "Journal Entries"; - - using (var client = new System.Net.Http.HttpClient()) - { - var baseUri = _baseConfig["ApiUrl"]; - client.BaseAddress = new System.Uri(baseUri); - client.DefaultRequestHeaders.Accept.Clear(); - var response = await client.GetAsync(baseUri + "financials/journalentries"); - if (response.IsSuccessStatusCode) - { - var responseJson = await response.Content.ReadAsStringAsync(); - return View(model: responseJson); - } - } - - return View(); + var responseJson = await response.Content.ReadAsStringAsync(); + return View(model: responseJson); } + } + + return View(); + } - public async System.Threading.Tasks.Task GeneralLedger() + public async System.Threading.Tasks.Task TrialBalance() + { + ViewBag.PageContentHeader = "Trial Balance"; + + using (var client = new System.Net.Http.HttpClient()) + { + var baseUri = _baseConfig!["ApiUrl"]; + client.BaseAddress = new System.Uri(baseUri!); + client.DefaultRequestHeaders.Accept.Clear(); + var response = await client.GetAsync(baseUri + "financials/trialbalance"); + if (response.IsSuccessStatusCode) { - ViewBag.PageContentHeader = "General Ledger"; - - using (var client = new System.Net.Http.HttpClient()) - { - var baseUri = _baseConfig["ApiUrl"]; - client.BaseAddress = new System.Uri(baseUri); - client.DefaultRequestHeaders.Accept.Clear(); - var response = await client.GetAsync(baseUri + "financials/generalledger"); - if (response.IsSuccessStatusCode) - { - var responseJson = await response.Content.ReadAsStringAsync(); - return View(model: responseJson); - } - } - - return View(); + var responseJson = await response.Content.ReadAsStringAsync(); + var trialBalanceModel = Newtonsoft.Json.JsonConvert.DeserializeObject>(responseJson); + return View(trialBalanceModel); } + } + + return View(); + } - public async System.Threading.Tasks.Task TrialBalance() + public async System.Threading.Tasks.Task BalanceSheet() + { + ViewBag.PageContentHeader = "Balance Sheet"; + + using (var client = new System.Net.Http.HttpClient()) + { + var baseUri = _baseConfig!["ApiUrl"]; + client.BaseAddress = new System.Uri(baseUri!); + client.DefaultRequestHeaders.Accept.Clear(); + var response = await client.GetAsync(baseUri + "financials/balancesheet"); + if (response.IsSuccessStatusCode) { - ViewBag.PageContentHeader = "Trial Balance"; - - using (var client = new System.Net.Http.HttpClient()) - { - var baseUri = _baseConfig["ApiUrl"]; - client.BaseAddress = new System.Uri(baseUri); - client.DefaultRequestHeaders.Accept.Clear(); - var response = await client.GetAsync(baseUri + "financials/trialbalance"); - if (response.IsSuccessStatusCode) - { - var responseJson = await response.Content.ReadAsStringAsync(); - var trialBalanceModel = Newtonsoft.Json.JsonConvert.DeserializeObject>(responseJson); - return View(trialBalanceModel); - } - } - - return View(); + var responseJson = await response.Content.ReadAsStringAsync(); + var balanceSheetModel = Newtonsoft.Json.JsonConvert.DeserializeObject>(responseJson); + return View(balanceSheetModel); } + } + return View(); + // return View(new List()); // Use this statement to test the view with an empty balance sheet + + //var Dto = _financialService.BalanceSheet().ToList(); + //var dt = Helpers.CollectionHelper.ConvertTo(Dto); + //var incomestatement = _financialService.IncomeStatement(); + //var netincome = incomestatement.Where(a => a.IsExpense == false).Sum(a => a.Amount) - incomestatement.Where(a => a.IsExpense == true).Sum(a => a.Amount); + + // TODO: Add logic to get the correct account for accumulated profit/loss. Currently, the account code is hard-coded here. + // Solution 1: Add two columns in general ledger setting for the account id of accumulated profit and loss. + // Solution 2: Add column to Account table to flag if account is net income (profit and loss) + //if (netincome < 0) + //{ + // var loss = Dto.Where(a => a.AccountCode == "30500").FirstOrDefault(); + // loss.Amount = netincome; + //} + //else + //{ + // var profit = Dto.Where(a => a.AccountCode == "30400").FirstOrDefault(); + // profit.Amount = netincome; + //} + + //return View(Dto); + } + + public async Task IncomeStatement() + { + ViewBag.PageContentHeader = "Income Statement"; + + using (var client = new System.Net.Http.HttpClient()) + { + var baseUri = _baseConfig!["ApiUrl"]; + client.BaseAddress = new System.Uri(baseUri!); + client.DefaultRequestHeaders.Accept.Clear(); - public async System.Threading.Tasks.Task BalanceSheet() + try { - ViewBag.PageContentHeader = "Balance Sheet"; - - using (var client = new System.Net.Http.HttpClient()) - { - var baseUri = _baseConfig["ApiUrl"]; - client.BaseAddress = new System.Uri(baseUri); - client.DefaultRequestHeaders.Accept.Clear(); - var response = await client.GetAsync(baseUri + "financials/balancesheet"); - if (response.IsSuccessStatusCode) - { - var responseJson = await response.Content.ReadAsStringAsync(); - var balanceSheetModel = Newtonsoft.Json.JsonConvert.DeserializeObject>(responseJson); - return View(balanceSheetModel); - } - } - - return View(); - //var Dto = _financialService.BalanceSheet().ToList(); - //var dt = Helpers.CollectionHelper.ConvertTo(Dto); - //var incomestatement = _financialService.IncomeStatement(); - //var netincome = incomestatement.Where(a => a.IsExpense == false).Sum(a => a.Amount) - incomestatement.Where(a => a.IsExpense == true).Sum(a => a.Amount); - - // TODO: Add logic to get the correct account for accumulated profit/loss. Currently, the account code is hard-coded here. - // Solution 1: Add two columns in general ledger setting for the account id of accumulated profit and loss. - // Solution 2: Add column to Account table to flag if account is net income (profit and loss) - //if (netincome < 0) - //{ - // var loss = Dto.Where(a => a.AccountCode == "30500").FirstOrDefault(); - // loss.Amount = netincome; - //} - //else - //{ - // var profit = Dto.Where(a => a.AccountCode == "30400").FirstOrDefault(); - // profit.Amount = netincome; - //} - - //return View(Dto); + var response = await client.GetAsync(baseUri + "financials/incomestatement"); + if (response.IsSuccessStatusCode) + { + var responseJson = await response.Content.ReadAsStringAsync(); + var incomeStatementModel = Newtonsoft.Json.JsonConvert.DeserializeObject>(responseJson); + return View(incomeStatementModel); + } + else + { + ViewBag.Error = "Failed to fetch income statement data."; + } } - - public async System.Threading.Tasks.Task IncomeStatement() + catch (Exception ex) { - ViewBag.PageContentHeader = "Income Statement"; - - using (var client = new System.Net.Http.HttpClient()) - { - var baseUri = _baseConfig["ApiUrl"]; - client.BaseAddress = new System.Uri(baseUri); - client.DefaultRequestHeaders.Accept.Clear(); - var response = await client.GetAsync(baseUri + "financials/incomestatement"); - if (response.IsSuccessStatusCode) - { - var responseJson = await response.Content.ReadAsStringAsync(); - var incomeStatementModel = Newtonsoft.Json.JsonConvert.DeserializeObject>(responseJson); - return View(incomeStatementModel); - } - } - - return View(); - //var Dto = _financialService.IncomeStatement(); - //return View(Dto); + ViewBag.Error = $"Error: {ex.Message}"; } + } - public IActionResult Banks() - { - ViewBag.PageContentHeader = "Cash/Banks"; + return View(new List()); + } - var banks = GetAsync>("financials/cashbanks").Result; - return View(banks); - } + public IActionResult Banks() + { + ViewBag.PageContentHeader = "Cash/Banks"; + + var banks = GetAsync>("financials/cashbanks").Result; + + return View(banks); } + + + + } } diff --git a/src/AccountGoWeb/Controllers/GoodController.cs b/src/AccountGoWeb/Controllers/GoodController.cs new file mode 100644 index 000000000..93b676218 --- /dev/null +++ b/src/AccountGoWeb/Controllers/GoodController.cs @@ -0,0 +1,74 @@ +using Microsoft.AspNetCore.Mvc; + +namespace AccountGoWeb.Controllers +{ + public class GoodController : Controller + { + protected IConfiguration? _configuration; + + protected HttpResponseMessage Get(string uri) + { + string responseJson = string.Empty; + using (var client = new HttpClient()) + { + string? baseUri = _configuration!["ApiUrl"]; + client.BaseAddress = new System.Uri(baseUri!); + client.DefaultRequestHeaders.Accept.Clear(); + var response = client.GetAsync(baseUri + uri); + return response.Result; + } + } + + protected HttpResponseMessage Post(string uri, StringContent data) + { + string responseJson = string.Empty; + using (var client = new HttpClient()) + { + string? baseUri = _configuration!["ApiUrl"]; + client.BaseAddress = new System.Uri(baseUri!); + client.DefaultRequestHeaders.Accept.Clear(); + client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json")); + //client.DefaultRequestHeaders.Add("UserName", GetCurrentUserName()); + + var response = client.PostAsync(baseUri + uri, data); + return response.Result; + } + } + + protected async System.Threading.Tasks.Task GetAsync(string uri) + { + string responseJson = string.Empty; + using (var client = new HttpClient()) + { + string? baseUri = _configuration!["ApiUrl"]; + client.BaseAddress = new System.Uri(baseUri!); + client.DefaultRequestHeaders.Accept.Clear(); + var response = await client.GetAsync(baseUri + uri); + if (response.IsSuccessStatusCode) + { + responseJson = await response.Content.ReadAsStringAsync(); + } + } + return Newtonsoft.Json.JsonConvert.DeserializeObject(responseJson)!; + } + + protected async System.Threading.Tasks.Task PostAsync(string uri, StringContent data) + { + string responseJson = string.Empty; + using (var client = new HttpClient()) + { + string? baseUri = _configuration!["ApiUrl"]; + client.BaseAddress = new System.Uri(baseUri!); + client.DefaultRequestHeaders.Accept.Clear(); + //client.DefaultRequestHeaders.Add("UserName", GetCurrentUserName()); + + var response = await client.PostAsync(baseUri + uri, data); + if (response.IsSuccessStatusCode) + { + responseJson = await response.Content.ReadAsStringAsync(); + } + } + return Newtonsoft.Json.JsonConvert.DeserializeObject(responseJson)!; + } + } +} diff --git a/src/AccountGoWeb/Controllers/HomeController.cs b/src/AccountGoWeb/Controllers/HomeController.cs index d7b5a2def..ee4b0b00a 100644 --- a/src/AccountGoWeb/Controllers/HomeController.cs +++ b/src/AccountGoWeb/Controllers/HomeController.cs @@ -1,9 +1,8 @@ using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Configuration; namespace AccountGoWeb.Controllers { - [Microsoft.AspNetCore.Authorization.Authorize] + //[Microsoft.AspNetCore.Authorization.Authorize] public class HomeController : BaseController { public HomeController(IConfiguration config) @@ -14,7 +13,7 @@ public HomeController(IConfiguration config) public IActionResult Index() { ViewBag.PageContentHeader = "Dashboard"; - ViewBag.ApiMontlySales = _baseConfig["ApiUrl"] + "sales/getmonthlysales"; + ViewBag.ApiMontlySales = _baseConfig!["ApiUrl"] + "sales/getmonthlysales"; return View(); } } diff --git a/src/AccountGoWeb/Controllers/InventoryController.cs b/src/AccountGoWeb/Controllers/InventoryController.cs index e15c5645b..e357ecce3 100644 --- a/src/AccountGoWeb/Controllers/InventoryController.cs +++ b/src/AccountGoWeb/Controllers/InventoryController.cs @@ -1,26 +1,28 @@ using Dto.Inventory; using Microsoft.AspNetCore.Mvc; -using System.Net.Http; namespace AccountGoWeb.Controllers { - [Microsoft.AspNetCore.Authorization.Authorize] + // [Microsoft.AspNetCore.Authorization.Authorize] public class InventoryController : BaseController { - public InventoryController(Microsoft.Extensions.Configuration.IConfiguration config) + private readonly ILogger _logger; + public InventoryController(Microsoft.Extensions.Configuration.IConfiguration config, + ILogger logger) { _baseConfig = config; Models.SelectListItemHelper._config = config; + _logger = logger; } - public async System.Threading.Tasks.Task Items() + public async Task Index() { ViewBag.PageContentHeader = "Items"; using (var client = new System.Net.Http.HttpClient()) { - var baseUri = _baseConfig["ApiUrl"]; - client.BaseAddress = new System.Uri(baseUri); + var baseUri = _baseConfig!["ApiUrl"]; + client.BaseAddress = new System.Uri(baseUri!); client.DefaultRequestHeaders.Accept.Clear(); var response = await client.GetAsync(baseUri + "inventory/items"); if (response.IsSuccessStatusCode) @@ -33,14 +35,14 @@ public async System.Threading.Tasks.Task Items() return View(); } - public async System.Threading.Tasks.Task ICJ() + public async Task ICJ() { ViewBag.PageContentHeader = "Inventory Control Journal"; using (var client = new System.Net.Http.HttpClient()) { - var baseUri = _baseConfig["ApiUrl"]; - client.BaseAddress = new System.Uri(baseUri); + var baseUri = _baseConfig!["ApiUrl"]; + client.BaseAddress = new System.Uri(baseUri!); client.DefaultRequestHeaders.Accept.Clear(); var response = await client.GetAsync(baseUri + "inventory/icj"); if (response.IsSuccessStatusCode) @@ -53,9 +55,10 @@ public async System.Threading.Tasks.Task ICJ() return View(); } - public IActionResult Item(int id = -1) + public IActionResult Item(int id) { - Item itemModel = null; + _logger.LogInformation("GetItem: " + id); + Item? itemModel = null; if (id == -1) { ViewBag.PageContentHeader = "Item Customer"; @@ -76,6 +79,39 @@ public IActionResult Item(int id = -1) return View(itemModel); } + public IActionResult AddItem(){ + ViewBag.PageContentHeader = "New Item"; + + ViewBag.ItemCategories = Models.SelectListItemHelper.ItemCategories(); + ViewBag.Measurements = Models.SelectListItemHelper.UnitOfMeasurements(); + ViewBag.ItemTaxGroups = Models.SelectListItemHelper.ItemTaxGroups(); + ViewBag.PreferredVendorId = Models.SelectListItemHelper.Vendors(); + ViewBag.Accounts = Models.SelectListItemHelper.Accounts(); + + Item itemModel = new Item(); + + return View(itemModel); + } + + [HttpPost] + public IActionResult AddItem(Item itemModel){ + ViewBag.PageContentHeader = "New Item"; + + if (ModelState.IsValid) { + _logger.LogInformation("Item Model is Valid: " + itemModel.Description); + var serialize = Newtonsoft.Json.JsonConvert.SerializeObject(itemModel); + var content = new StringContent(serialize); + content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json"); + var response = Post("Inventory/SaveItem", content); + _logger.LogInformation("Response: " + response); + if (response.IsSuccessStatusCode) + return RedirectToAction("Items"); + } + + return View(itemModel); + } + + [HttpPost] public IActionResult SaveItem(Item itemModel) { if (ModelState.IsValid) @@ -86,7 +122,7 @@ public IActionResult SaveItem(Item itemModel) var response = PostAsync("inventory/saveitem", content); - return RedirectToAction("Items"); + return RedirectToAction("Index"); } ViewBag.Accounts = Models.SelectListItemHelper.Accounts(); @@ -94,13 +130,12 @@ public IActionResult SaveItem(Item itemModel) ViewBag.Measurements = Models.SelectListItemHelper.UnitOfMeasurements(); ViewBag.ItemCategories = Models.SelectListItemHelper.ItemCategories(); - if (itemModel.Id > 0) ViewBag.PageContentHeader = "Item Item"; else ViewBag.PageContentHeader = "New Card"; - return View("Item", itemModel); + return View("Index"); } } } diff --git a/src/AccountGoWeb/Controllers/PurchasingController.cs b/src/AccountGoWeb/Controllers/PurchasingController.cs index d8215259c..e51d8364e 100644 --- a/src/AccountGoWeb/Controllers/PurchasingController.cs +++ b/src/AccountGoWeb/Controllers/PurchasingController.cs @@ -1,16 +1,17 @@ -using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Configuration; -using System.Net.Http; +using Dto.Purchasing; +using Microsoft.AspNetCore.Mvc; namespace AccountGoWeb.Controllers { - [Microsoft.AspNetCore.Authorization.Authorize] + //[Microsoft.AspNetCore.Authorization.Authorize] public class PurchasingController : BaseController { - public PurchasingController(IConfiguration config) + private readonly ILogger _logger; + public PurchasingController(IConfiguration config, ILogger logger) { _baseConfig = config; Models.SelectListItemHelper._config = config; + _logger = logger; } public IActionResult Index() @@ -24,7 +25,7 @@ public IActionResult PurchaseOrders() string purchaseOrders = GetAsync("purchasing/purchaseorders") .Result - .ToString(); + .ToString()!; return View(model: purchaseOrders); } @@ -32,21 +33,106 @@ public IActionResult PurchaseOrders() public IActionResult AddPurchaseOrder() { ViewBag.PageContentHeader = "Add Purchase Order"; + PurchaseOrder purchaseOrderModel = new PurchaseOrder(); + purchaseOrderModel.PurchaseOrderLines = new List { new PurchaseOrderLine { + Amount = 0, + Discount = 0, + ItemId = 1, + Quantity = 1, + } }; + purchaseOrderModel.No = new System.Random().Next(1, 99999).ToString(); ViewBag.Vendors = Models.SelectListItemHelper.Vendors(); + ViewBag.PaymentTerms = Models.SelectListItemHelper.PaymentTerms(); + ViewBag.Items = Models.SelectListItemHelper.Items(); + ViewBag.Measurements = Models.SelectListItemHelper.Measurements(); - return View(); + return View(purchaseOrderModel); + } + + [HttpPost] + public IActionResult AddPurchaseOrder(PurchaseOrder purchaseOrder, string addRowBtn) + { + ViewBag.PageContentHeader = "Add Purchase Order"; + + if (!string.IsNullOrEmpty(addRowBtn)) + { + purchaseOrder.PurchaseOrderLines.Add(new PurchaseOrderLine + { + Amount = 0, + Discount = 0, + ItemId = 1, + Quantity = 1 + }); + + ViewBag.Vendors = Models.SelectListItemHelper.Vendors(); + ViewBag.PaymentTerms = Models.SelectListItemHelper.PaymentTerms(); + ViewBag.Items = Models.SelectListItemHelper.Items(); + ViewBag.Measurements = Models.SelectListItemHelper.Measurements(); + + return View(purchaseOrder); + } + else if (ModelState.IsValid) + { + var serialize = Newtonsoft.Json.JsonConvert.SerializeObject(purchaseOrder); + var content = new StringContent(serialize); + content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json"); + + var response = PostAsync("purchasing/savepurchaseorder", content); + + return RedirectToAction("PurchaseOrders"); + } + + return View("PurchaseOrders"); + } + + public IActionResult PurchaseInvoice(int id) + { + ViewBag.PageContentHeader = "Purchase Invoice"; + + PurchaseInvoice? purchaseInvoiceModel = null; + + if (id == 0) + { + ViewBag.PageContentHeader = "New Purchase Invoice"; + return View("PurchaseInvoice"); + } + else + { + purchaseInvoiceModel = GetAsync("Purchasing/PurchaseInvoice?id=" + id).Result; + } + + ViewBag.Vendors = Models.SelectListItemHelper.Vendors(); + ViewBag.PaymentTerms = Models.SelectListItemHelper.PaymentTerms(); + ViewBag.Items = Models.SelectListItemHelper.Items(); + ViewBag.Measurements = Models.SelectListItemHelper.Measurements(); + + return View(purchaseInvoiceModel); } - public IActionResult PurchaseOrder(int purchId = 0) + + public IActionResult PurchaseOrder(int id) { ViewBag.PageContentHeader = "Purchase Order"; - var purchOrderDto = GetAsync("purchasing/purchaseorder?id=" + purchId).Result; + PurchaseOrder? purchaseOrderModel = null; + + if (id == 0) + { + ViewBag.PageContentHeader = "New Purchase Order"; + return View(); + } + else + { + purchaseOrderModel = GetAsync("Purchasing/PurchaseOrder?id=" + id).Result; + } ViewBag.Vendors = Models.SelectListItemHelper.Vendors(); + ViewBag.PaymentTerms = Models.SelectListItemHelper.PaymentTerms(); + ViewBag.Items = Models.SelectListItemHelper.Items(); + ViewBag.Measurements = Models.SelectListItemHelper.Measurements(); - return View(); + return View(purchaseOrderModel); } public async System.Threading.Tasks.Task PurchaseInvoices() @@ -54,8 +140,8 @@ public async System.Threading.Tasks.Task PurchaseInvoices() ViewBag.PageContentHeader = "Purchase Invoices"; using (var client = new HttpClient()) { - var baseUri = _baseConfig["ApiUrl"]; - client.BaseAddress = new System.Uri(baseUri); + var baseUri = _baseConfig!["ApiUrl"]; + client.BaseAddress = new System.Uri(baseUri!); client.DefaultRequestHeaders.Accept.Clear(); var response = await client.GetAsync(baseUri + "purchasing/purchaseinvoices"); if (response.IsSuccessStatusCode) @@ -67,18 +153,59 @@ public async System.Threading.Tasks.Task PurchaseInvoices() return View(); } - public IActionResult AddPurchaseInvoice(int purchId = 0) + public IActionResult AddPurchaseInvoice() { ViewBag.PageContentHeader = "New Invoice"; - return View(); + PurchaseInvoice purchaseInvoiceModel = new PurchaseInvoice(); + purchaseInvoiceModel.PurchaseInvoiceLines = new List { new PurchaseInvoiceLine { + Amount = 0, + Discount = 0, + ItemId = 1, + Quantity = 1, + } }; + purchaseInvoiceModel.No = new System.Random().Next(1, 99999).ToString(); + + ViewBag.Vendors = Models.SelectListItemHelper.Vendors(); + ViewBag.PaymentTerms = Models.SelectListItemHelper.PaymentTerms(); + ViewBag.Items = Models.SelectListItemHelper.Items(); + ViewBag.Measurements = Models.SelectListItemHelper.Measurements(); + + return View(purchaseInvoiceModel); } - public IActionResult PurchaseInvoice(int id) + [HttpPost] + public async System.Threading.Tasks.Task AddPurchaseInvoice(PurchaseInvoice purchaseInvoice, string addRowBtn) { - ViewBag.PageContentHeader = "Purchase Invoice"; + ViewBag.PageContentHeader = "New Invoice"; + if (!string.IsNullOrEmpty(addRowBtn)) + { + purchaseInvoice.PurchaseInvoiceLines.Add(new PurchaseInvoiceLine + { + Amount = 0, + Discount = 0, + ItemId = 1, + Quantity = 1 + }); - ViewBag.Vendors = Models.SelectListItemHelper.Vendors(); + ViewBag.Vendors = Models.SelectListItemHelper.Vendors(); + ViewBag.PaymentTerms = Models.SelectListItemHelper.PaymentTerms(); + ViewBag.Items = Models.SelectListItemHelper.Items(); + ViewBag.Measurements = Models.SelectListItemHelper.Measurements(); + + return View(purchaseInvoice); + } + else if (ModelState.IsValid) + { + var serialize = Newtonsoft.Json.JsonConvert.SerializeObject(purchaseInvoice); + var content = new StringContent(serialize); + content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json"); + + var response = await PostAsync("Purchasing/SavePurchaseInvoice", content); + _logger.LogInformation("Purchase Invoice Saved" + purchaseInvoice.Id); + + return RedirectToAction("PurchaseInvoices"); + } return View(); } @@ -95,8 +222,8 @@ public async System.Threading.Tasks.Task Vendors() ViewBag.PageContentHeader = "Vendors"; using (var client = new HttpClient()) { - var baseUri = _baseConfig["ApiUrl"]; - client.BaseAddress = new System.Uri(baseUri); + var baseUri = _baseConfig!["ApiUrl"]; + client.BaseAddress = new System.Uri(baseUri!); client.DefaultRequestHeaders.Accept.Clear(); var response = await client.GetAsync(baseUri + "purchasing/vendors"); if (response.IsSuccessStatusCode) @@ -109,7 +236,7 @@ public async System.Threading.Tasks.Task Vendors() } public IActionResult Vendor(int id = -1) { - Dto.Purchasing.Vendor vendorModel = null; + Dto.Purchasing.Vendor? vendorModel = null; if (id == -1) { ViewBag.PageContentHeader = "New Vendor"; @@ -169,7 +296,7 @@ public IActionResult Payment(int id) VendorId = invoice.VendorId, VendorName = invoice.VendorName, InvoiceAmount = invoice.Amount, - AmountPaid = invoice.AmountPaid, + AmountPaid = invoice.AmountPaid, Date = invoice.InvoiceDate }; @@ -177,7 +304,7 @@ public IActionResult Payment(int id) return View(model); } - + [HttpPost] public IActionResult Payment(Models.Purchasing.Payment model) { diff --git a/src/AccountGoWeb/Controllers/QuotationsController.cs b/src/AccountGoWeb/Controllers/QuotationsController.cs index cbe402648..85174e4b1 100644 --- a/src/AccountGoWeb/Controllers/QuotationsController.cs +++ b/src/AccountGoWeb/Controllers/QuotationsController.cs @@ -1,14 +1,17 @@ -using System.Net.Http; +using Dto.Sales; using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Configuration; namespace AccountGoWeb.Controllers { - [Microsoft.AspNetCore.Authorization.Authorize] - public class QuotationsController : BaseController + //[Microsoft.AspNetCore.Authorization.Authorize] + public class QuotationsController : GoodController { - public QuotationsController(IConfiguration config) { - _baseConfig = config; + //private readonly IConfiguration _configuration; + private readonly ILogger _logger; + public QuotationsController(IConfiguration config, ILogger logger) + { + _configuration = config; + _logger = logger; } public IActionResult Index() @@ -22,8 +25,8 @@ public async System.Threading.Tasks.Task Quotations() using (var client = new HttpClient()) { - var baseUri = _baseConfig["ApiUrl"]; - client.BaseAddress = new System.Uri(baseUri); + var baseUri = _configuration!["ApiUrl"]; + client.BaseAddress = new System.Uri(baseUri!); client.DefaultRequestHeaders.Accept.Clear(); var response = await client.GetAsync(baseUri + "sales/quotations"); if (response.IsSuccessStatusCode) @@ -36,18 +39,106 @@ public async System.Threading.Tasks.Task Quotations() return View(); } + [HttpGet] public IActionResult AddSalesQuotation() { ViewBag.PageContentHeader = "Add Sales Quotation"; - return View(); + SalesQuotation model = new SalesQuotation(); + model.SalesQuotationLines = new List { new SalesQuotationLine { + Amount = 0, + Quantity = 1, + Discount = 0, + ItemId = 1, + MeasurementId = 1, + } }; + model.No = new System.Random().Next(1, 99999).ToString(); // TODO: Replace with system generated numbering. + + ViewBag.Customers = Models.SelectListItemHelper.Customers(); + ViewBag.Items = Models.SelectListItemHelper.Items(); + ViewBag.PaymentTerms = Models.SelectListItemHelper.PaymentTerms(); + ViewBag.Measurements = Models.SelectListItemHelper.Measurements(); + + return View(model); } - public IActionResult Quotation() + [HttpPost] + public async Task AddSalesQuotation(Dto.Sales.SalesQuotation model, string? addRowBtn) { - ViewBag.PageContentHeader = "Sales Quotation"; + if (!string.IsNullOrEmpty(addRowBtn)) + { + _logger.LogInformation("Add Row Button Clicked"); + model.SalesQuotationLines.Add(new SalesQuotationLine + { + Amount = 0, + Quantity = 1, + Discount = 0, + ItemId = 1, + MeasurementId = 1, + }); + ViewBag.Customers = Models.SelectListItemHelper.Customers(); + ViewBag.Items = Models.SelectListItemHelper.Items(); + ViewBag.PaymentTerms = Models.SelectListItemHelper.PaymentTerms(); + ViewBag.Measurements = Models.SelectListItemHelper.Measurements(); - return View(); + return View(model); + + } + else if (ModelState.IsValid) + { + var serialize = Newtonsoft.Json.JsonConvert.SerializeObject(model); + var content = new StringContent(serialize); + content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json"); + + using (var client = new HttpClient()) + { + var baseUri = _configuration!["ApiUrl"]; + client.BaseAddress = new Uri(baseUri!); + var response = await client.PostAsync("sales/savequotation", content); + + if (response.IsSuccessStatusCode) { + _logger.LogInformation("Quotation has been successfully saved."); + } else { + _logger.LogInformation("Quotation save failed."); + } + return RedirectToAction("quotations"); + } + } else { + _logger.LogInformation("Model State is not valid."); + return RedirectToAction("quotations"); + } + + } + + [HttpGet] + public IActionResult Quotation(int id) + { + ViewBag.PageContentHeader = "Sales"; + + SalesQuotation? model = null; + + if (id == 0) + { + ViewBag.PageContentHeader = "Add Sales Quotation"; + return View("AddSalesQuotation"); + } + else + { + model = GetAsync("Sales/Quotation?id=" + id).Result; + @ViewBag.Id = model.Id; + @ViewBag.QuotationDate = model.QuotationDate; + @ViewBag.CustomerName = model.CustomerName; + @ViewBag.PaymentTermId = model.PaymentTermId; + @ViewBag.SalesQuotationLines = model.SalesQuotationLines; + @ViewBag.TotalAmount = model.Amount; + } + + @ViewBag.Customers = Models.SelectListItemHelper.Customers(); + ViewBag.Items = Models.SelectListItemHelper.Items(); + @ViewBag.PaymentTerms = Models.SelectListItemHelper.PaymentTerms(); + @ViewBag.Measurements = Models.SelectListItemHelper.Measurements(); + + return View(model); } } } diff --git a/src/AccountGoWeb/Controllers/SPAProxyController.cs b/src/AccountGoWeb/Controllers/SPAProxyController.cs index 67313350c..b17b3bbd4 100644 --- a/src/AccountGoWeb/Controllers/SPAProxyController.cs +++ b/src/AccountGoWeb/Controllers/SPAProxyController.cs @@ -1,10 +1,7 @@ -using System.Net.Http; -using System.Text; -using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Configuration; using Newtonsoft.Json; using Newtonsoft.Json.Linq; +using System.Text; namespace AccountGoWeb.Controllers { diff --git a/src/AccountGoWeb/Controllers/SalesController.cs b/src/AccountGoWeb/Controllers/SalesController.cs index ec582bf86..81ccb0eb9 100644 --- a/src/AccountGoWeb/Controllers/SalesController.cs +++ b/src/AccountGoWeb/Controllers/SalesController.cs @@ -1,19 +1,21 @@ using AccountGoWeb.Models; using Dto.Sales; using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Configuration; -using System.Collections.Generic; -using System.Net.Http; +using Newtonsoft.Json; namespace AccountGoWeb.Controllers { - [Microsoft.AspNetCore.Authorization.Authorize] - public class SalesController : BaseController + //[Microsoft.AspNetCore.Authorization.Authorize] + public class SalesController : GoodController { - public SalesController(IConfiguration config) + // private readonly IConfiguration _configuration; + private readonly ILogger _logger; + + public SalesController(IConfiguration config, ILogger logger) { - _baseConfig = config; + _configuration = config; Models.SelectListItemHelper._config = config; + _logger = logger; } public IActionResult Index() @@ -26,8 +28,8 @@ public async System.Threading.Tasks.Task SalesOrders() ViewBag.PageContentHeader = "Sales Orders"; using (var client = new HttpClient()) { - var baseUri = _baseConfig["ApiUrl"]; - client.BaseAddress = new System.Uri(baseUri); + var baseUri = _configuration!["ApiUrl"]; + client.BaseAddress = new System.Uri(baseUri!); client.DefaultRequestHeaders.Accept.Clear(); var response = await client.GetAsync(baseUri + "sales/salesorders"); if (response.IsSuccessStatusCode) @@ -42,26 +44,114 @@ public async System.Threading.Tasks.Task SalesOrders() public IActionResult AddSalesOrder() { ViewBag.PageContentHeader = "Add Sales Order"; - - return View(); + SalesOrder salesOrderModel = new SalesOrder(); + salesOrderModel.SalesOrderLines = new List { new SalesOrderLine { + Amount = 0, + Discount = 0, + ItemId = 1, + Quantity = 1, + } }; + salesOrderModel.No = new System.Random().Next(1, 99999).ToString(); + + @ViewBag.Customers = Models.SelectListItemHelper.Customers(); + @ViewBag.PaymentTerms = Models.SelectListItemHelper.PaymentTerms(); + @ViewBag.Items = Models.SelectListItemHelper.Items(); + @ViewBag.Measurements = Models.SelectListItemHelper.Measurements(); + + return View(salesOrderModel); } [HttpPost] - public IActionResult AddSalesOrder(object Dto) + public IActionResult AddSalesOrder(SalesOrder Dto, string addRowBtn) { - return Ok(); + if (!string.IsNullOrEmpty(addRowBtn)) + { + Dto.SalesOrderLines.Add(new SalesOrderLine + { + Amount = 0, + Quantity = 1, + Discount = 0, + ItemId = 1, + MeasurementId = 1, + }); + + ViewBag.Customers = Models.SelectListItemHelper.Customers(); + ViewBag.Items = Models.SelectListItemHelper.Items(); + ViewBag.PaymentTerms = Models.SelectListItemHelper.PaymentTerms(); + ViewBag.Measurements = Models.SelectListItemHelper.Measurements(); + + return View(Dto); + } + else if (ModelState.IsValid) + { + var serialize = Newtonsoft.Json.JsonConvert.SerializeObject(Dto); + var content = new StringContent(serialize); + content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json"); + + var response = Post("Sales/addsalesorder", content); + if (response.IsSuccessStatusCode) + return RedirectToAction("salesorders"); + } + @ViewBag.Customers = Models.SelectListItemHelper.Customers(); + @ViewBag.PaymentTerms = Models.SelectListItemHelper.PaymentTerms(); + @ViewBag.Measurements = Models.SelectListItemHelper.Measurements(); + + return RedirectToAction("salesorders"); } - + public IActionResult SalesOrder(int id) { ViewBag.PageContentHeader = "Sales Order"; - return View(); + SalesOrder? salesOrderModel = null; + if (id == -1) + { + ViewBag.PageContentHeader = "Add Sales Order"; + return View("AddSalesOrder"); + + } + else + { + salesOrderModel = GetAsync("Sales/SalesOrder?id=" + id).Result; + ViewBag.CustomerName = salesOrderModel.CustomerName; + ViewBag.OrderDate = salesOrderModel.OrderDate; + ViewBag.SalesOrderLines = salesOrderModel.SalesOrderLines; + ViewBag.TotalAmount = salesOrderModel.Amount; + } + + @ViewBag.Customers = Models.SelectListItemHelper.Customers(); + @ViewBag.PaymentTerms = Models.SelectListItemHelper.PaymentTerms(); + @ViewBag.Items = Models.SelectListItemHelper.Items(); + @ViewBag.Measurements = Models.SelectListItemHelper.Measurements(); + + return View(salesOrderModel); } public IActionResult SalesInvoice(int id) { ViewBag.PageContentHeader = "Sales Invoice"; - return View(); + SalesInvoice? salesInvoiceModel = null; + + if (id == 0) + { + ViewBag.PageContentHeader = "Add Sales Invoice"; + return View("AddSalesInvoice"); + } + else + { + salesInvoiceModel = GetAsync("Sales/SalesInvoice?id=" + id).Result; + ViewBag.Id = salesInvoiceModel.Id; + ViewBag.CustomerName = salesInvoiceModel.CustomerName; + ViewBag.InvoiceDate = salesInvoiceModel.InvoiceDate; + ViewBag.SalesInvoiceLines = salesInvoiceModel.SalesInvoiceLines; + ViewBag.TotalAmount = salesInvoiceModel.Amount; + } + + @ViewBag.Customers = Models.SelectListItemHelper.Customers(); + @ViewBag.PaymentTerms = Models.SelectListItemHelper.PaymentTerms(); + @ViewBag.Items = Models.SelectListItemHelper.Items(); + @ViewBag.Measurements = Models.SelectListItemHelper.Measurements(); + + return View("SalesInvoice", salesInvoiceModel); } public async System.Threading.Tasks.Task SalesInvoices() @@ -69,8 +159,8 @@ public async System.Threading.Tasks.Task SalesInvoices() ViewBag.PageContentHeader = "Sales Invoices"; using (var client = new HttpClient()) { - var baseUri = _baseConfig["ApiUrl"]; - client.BaseAddress = new System.Uri(baseUri); + var baseUri = _configuration!["ApiUrl"]; + client.BaseAddress = new System.Uri(baseUri!); client.DefaultRequestHeaders.Accept.Clear(); var response = await client.GetAsync(baseUri + "sales/salesinvoices"); if (response.IsSuccessStatusCode) @@ -78,47 +168,164 @@ public async System.Threading.Tasks.Task SalesInvoices() var responseJson = await response.Content.ReadAsStringAsync(); return View(model: responseJson); } + + @ViewBag.Customers = Models.SelectListItemHelper.Customers(); + @ViewBag.PaymentTerms = Models.SelectListItemHelper.PaymentTerms(); + @ViewBag.Items = Models.SelectListItemHelper.Items(); + @ViewBag.Measurements = Models.SelectListItemHelper.Measurements(); } return View(); } + [HttpPost] + public async System.Threading.Tasks.Task SalesInvoice(SalesInvoice salesInvoiceModel) + { + if (ModelState.IsValid) + { + var serialize = Newtonsoft.Json.JsonConvert.SerializeObject(salesInvoiceModel); + var content = new StringContent(serialize); + content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json"); + string ReadAsStringAsync = await content.ReadAsStringAsync(); + _logger.LogInformation("SaveSalesInvoice: " + ReadAsStringAsync); + var response = Post("Sales/UpdateSalesInvoice", content); + + if (response.IsSuccessStatusCode) + { + return RedirectToAction("SalesInvoices"); + } + } + + ViewBag.Customers = SelectListItemHelper.Customers(); + ViewBag.PaymentTerms = SelectListItemHelper.PaymentTerms(); + ViewBag.Items = SelectListItemHelper.Items(); + ViewBag.Measurements = SelectListItemHelper.Measurements(); + ViewBag.TotalAmount = salesInvoiceModel.Amount; + + return View(salesInvoiceModel); + } + + [HttpGet] public IActionResult AddSalesInvoice() { ViewBag.PageContentHeader = "Add Sales Invoice"; - return View(); + SalesInvoice salesInvoiceModel = new SalesInvoice(); + salesInvoiceModel.SalesInvoiceLines = new List { new SalesInvoiceLine { + Amount = 0, + Discount = 0, + ItemId = 1, + Quantity = 1, + } }; + salesInvoiceModel.No = new System.Random().Next(1, 99999).ToString(); // TODO: Replace with system generated numbering. + + @ViewBag.Customers = Models.SelectListItemHelper.Customers(); + @ViewBag.PaymentTerms = Models.SelectListItemHelper.PaymentTerms(); + @ViewBag.Items = Models.SelectListItemHelper.Items(); + @ViewBag.Measurements = Models.SelectListItemHelper.Measurements(); + + return View(salesInvoiceModel); + } + + [HttpPost] + public async System.Threading.Tasks.Task AddSalesInvoice(SalesInvoice Dto, string? addRowBtn) + { + if (!string.IsNullOrEmpty(addRowBtn)) + { + Dto.SalesInvoiceLines!.Add(new SalesInvoiceLine + { + Amount = 0, + Quantity = 1, + Discount = 0, + ItemId = 1, + MeasurementId = 1, + }); + + ViewBag.Customers = Models.SelectListItemHelper.Customers(); + ViewBag.Items = Models.SelectListItemHelper.Items(); + ViewBag.PaymentTerms = Models.SelectListItemHelper.PaymentTerms(); + ViewBag.Measurements = Models.SelectListItemHelper.Measurements(); + + return View(Dto); + } + else if (ModelState.IsValid) + { + _logger.LogInformation("Posted value received: {Posted}", Dto.Posted); + var serialize = Newtonsoft.Json.JsonConvert.SerializeObject(Dto); + var content = new StringContent(serialize); + content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json"); + + _logger.LogInformation("AddSalesInvoice: " + await content.ReadAsStringAsync()); + var response = Post("Sales/CreateSalesInvoice", content); + + _logger.LogInformation("AddSalesInvoice response: " + response.ToString()); + if (response.IsSuccessStatusCode) + return RedirectToAction("salesinvoices"); + } + + ViewBag.Customers = Models.SelectListItemHelper.Customers(); + ViewBag.Items = Models.SelectListItemHelper.Items(); + ViewBag.PaymentTerms = Models.SelectListItemHelper.PaymentTerms(); + ViewBag.Measurements = Models.SelectListItemHelper.Measurements(); + + return View(Dto); } public async System.Threading.Tasks.Task SalesReceipts() { ViewBag.PageContentHeader = "Sales Receipts"; - using (var client = new HttpClient()) + try { - var baseUri = _baseConfig["ApiUrl"]; - client.BaseAddress = new System.Uri(baseUri); - client.DefaultRequestHeaders.Accept.Clear(); - var response = await client.GetAsync(baseUri + "sales/salesreceipts"); - if (response.IsSuccessStatusCode) + using (var client = new HttpClient()) { - var responseJson = await response.Content.ReadAsStringAsync(); - return View(model: responseJson); + var baseUri = _configuration!["ApiUrl"]; + client.BaseAddress = new Uri(baseUri!); + client.DefaultRequestHeaders.Accept.Clear(); + + var response = await client.GetAsync("sales/salesreceipts"); + if (response.IsSuccessStatusCode) + { + var responseJson = await response.Content.ReadAsStringAsync(); + return View(model: responseJson); + } + else + { + _logger.LogError("Failed to fetch sales receipts. API returned status code: {StatusCode}", response.StatusCode); + ViewBag.ErrorMessage = "Failed to load sales receipts. Please try again later."; + } } } - return View(); + catch (Exception ex) + { + _logger.LogError(ex, "An error occurred while fetching sales receipts."); + ViewBag.ErrorMessage = "An unexpected error occurred while loading sales receipts."; + } + + // Return the view with an error message if the API call fails + return View(model: "[]"); } + [HttpGet] public IActionResult AddReceipt() { - ViewBag.PageContentHeader = "New Receipt"; - - var model = new Models.Sales.AddReceipt(); - - ViewBag.Customers = Models.SelectListItemHelper.Customers(); - ViewBag.DebitAccounts = Models.SelectListItemHelper.CashBanks(); - ViewBag.CreditAccounts = Models.SelectListItemHelper.Accounts(); - ViewBag.CustomersDetail = Newtonsoft.Json.JsonConvert.SerializeObject(GetAsync>("sales/customers").Result); - - return View(model); + try + { + ViewBag.PageContentHeader = "New Receipt"; + ViewBag.Customers = Models.SelectListItemHelper.Customers(); + ViewBag.DebitAccounts = Models.SelectListItemHelper.CashBanks(); + ViewBag.CreditAccounts = Models.SelectListItemHelper.Accounts(); + ViewBag.CustomersDetail = Newtonsoft.Json.JsonConvert.SerializeObject( + GetAsync>("sales/customers").Result + ); + + var model = new Models.Sales.AddReceipt(); + return View(model); + } + catch (Exception ex) + { + _logger.LogError(ex, "An error occurred while preparing the Add Receipt page."); + ViewBag.ErrorMessage = "Failed to load the page for adding a receipt. Please try again later."; + return View(new Models.Sales.AddReceipt()); + } } [HttpPost] @@ -126,32 +333,49 @@ public IActionResult AddReceipt(Models.Sales.AddReceipt model) { if (ModelState.IsValid) { - var serialize = Newtonsoft.Json.JsonConvert.SerializeObject(model); - var content = new StringContent(serialize); - content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json"); - var response = Post("sales/savereceipt", content); - if(response.IsSuccessStatusCode) - return RedirectToAction("salesreceipts"); + try + { + var serialize = Newtonsoft.Json.JsonConvert.SerializeObject(model); + var content = new StringContent(serialize); + content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json"); + + var response = Post("sales/savereceipt", content); + if (response.IsSuccessStatusCode) + { + return RedirectToAction("SalesReceipts"); + } + else + { + _logger.LogError("Failed to save receipt. API returned status code: {StatusCode}", response.StatusCode); + ViewBag.ErrorMessage = "Failed to save the receipt. Please try again."; + } + } + catch (Exception ex) + { + _logger.LogError(ex, "An error occurred while saving the receipt."); + ViewBag.ErrorMessage = "An unexpected error occurred. Please try again."; + } } + // Reload dropdowns and return the view if validation or API call fails ViewBag.PageContentHeader = "New Receipt"; - ViewBag.Customers = Models.SelectListItemHelper.Customers(); ViewBag.DebitAccounts = Models.SelectListItemHelper.CashBanks(); ViewBag.CreditAccounts = Models.SelectListItemHelper.Accounts(); - ViewBag.CustomersDetail = Newtonsoft.Json.JsonConvert.SerializeObject(GetAsync>("sales/customers").Result); + ViewBag.CustomersDetail = Newtonsoft.Json.JsonConvert.SerializeObject( + GetAsync>("sales/customers").Result + ); return View(model); } - public async System.Threading.Tasks.Task Customers() { ViewBag.PageContentHeader = "Customers"; using (var client = new HttpClient()) { - var baseUri = _baseConfig["ApiUrl"]; - client.BaseAddress = new System.Uri(baseUri); + var baseUri = _configuration!["ApiUrl"]; + client.BaseAddress = new System.Uri(baseUri!); client.DefaultRequestHeaders.Accept.Clear(); var response = await client.GetAsync(baseUri + "sales/customers"); if (response.IsSuccessStatusCode) @@ -162,10 +386,10 @@ public async System.Threading.Tasks.Task Customers() } return View(); } - + public IActionResult Customer(int id = -1) { - Customer customerModel = null; + Customer? customerModel = null; if (id == -1) { ViewBag.PageContentHeader = "New Customer"; @@ -185,24 +409,50 @@ public IActionResult Customer(int id = -1) return View(customerModel); } - public IActionResult SaveCustomer(Customer customerModel) + [HttpPost] + public async System.Threading.Tasks.Task SaveSalesInvoice(SalesInvoice salesInvoiceModel) { if (ModelState.IsValid) { - var serialize = Newtonsoft.Json.JsonConvert.SerializeObject(customerModel); + var serialize = Newtonsoft.Json.JsonConvert.SerializeObject(salesInvoiceModel); var content = new StringContent(serialize); content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json"); - var response = PostAsync("sales/savecustomer", content); + string ReadAsStringAsync = await content.ReadAsStringAsync(); + _logger.LogInformation("SaveSalesInvoice: " + ReadAsStringAsync); + var response = Post("Sales/SaveSalesInvoice", content); + if (response.IsSuccessStatusCode) + { + return RedirectToAction("SalesInvoices"); + } + } + ViewBag.Customers = SelectListItemHelper.Customers(); + ViewBag.PaymentTerms = SelectListItemHelper.PaymentTerms(); + ViewBag.Items = SelectListItemHelper.Items(); + ViewBag.Measurements = SelectListItemHelper.Measurements(); + + return View("SalesInvoice", salesInvoiceModel); + } + + public async Task SaveCustomer(Customer customerModel) + { + if (ModelState.IsValid) + { + var serialize = Newtonsoft.Json.JsonConvert.SerializeObject(customerModel); + var content = new StringContent(serialize); + content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json"); + string ReadAsStringAsync = await content.ReadAsStringAsync(); + var response = await PostAsync("Sales/SaveCustomer", content); return RedirectToAction("Customers"); } - else { + else + { ViewBag.Accounts = SelectListItemHelper.Accounts(); ViewBag.TaxGroups = SelectListItemHelper.TaxGroups(); ViewBag.PaymentTerms = SelectListItemHelper.PaymentTerms(); } - if(customerModel.Id == -1) + if (customerModel.Id == -1) ViewBag.PageContentHeader = "New Customer"; else ViewBag.PageContentHeader = "Customer Card"; @@ -210,6 +460,7 @@ public IActionResult SaveCustomer(Customer customerModel) return View("Customer", customerModel); } + public IActionResult CustomerAllocations(int id) { ViewBag.PageContentHeader = "Customer Allocations"; @@ -217,38 +468,71 @@ public IActionResult CustomerAllocations(int id) return View(); } + // [HttpGet] public IActionResult Allocate(int id) { - ViewBag.PageContentHeader = "Receipt Allocation"; + Console.WriteLine($"Allocate called with ID: {id}"); - var model = new Models.Sales.Allocate(); + try + { + ViewBag.PageContentHeader = "Receipt Allocation"; - var receipt = GetAsync("sales/salesreceipt?id=" + id).Result; + var model = new Models.Sales.Allocate(); - ViewBag.CustomerName = receipt.CustomerName; - ViewBag.ReceiptNo = receipt.ReceiptNo; + // Fetch receipt details + var receipt = GetAsync("sales/salesreceipt?id=" + id).Result; + if (receipt == null) + { + Console.WriteLine($"Receipt not found for ID: {id}"); + _logger.LogError("Failed to fetch receipt with id: {id}", id); + return NotFound($"Receipt with id {id} not found."); + } + + ViewBag.CustomerName = receipt.CustomerName; + ViewBag.ReceiptNo = receipt.ReceiptNo; - model.CustomerId = receipt.CustomerId; - model.ReceiptId = receipt.Id; - model.Date = receipt.ReceiptDate; - model.Amount = receipt.Amount; - model.RemainingAmountToAllocate = receipt.RemainingAmountToAllocate; + model.CustomerId = receipt.CustomerId; + model.ReceiptId = receipt.Id; + model.Date = receipt.ReceiptDate; + model.Amount = receipt.Amount; + model.RemainingAmountToAllocate = receipt.RemainingAmountToAllocate; - var invoices = GetAsync>("sales/customerinvoices?id=" + receipt.CustomerId).Result; + // Fetch customer invoices + _logger.LogInformation("Calling API: sales/customerinvoices?id={id}", receipt.CustomerId); - foreach (var invoice in invoices) { - if (invoice.Posted && invoice.TotalAllocatedAmount < invoice.Amount) + var invoices = GetAsync>("sales/customerinvoices?id=" + receipt.CustomerId).Result; + if (invoices == null) { - model.AllocationLines.Add(new Models.Sales.AllocationLine() + _logger.LogError("Failed to fetch invoices for customer with id: {CustomerId}", receipt.CustomerId); + return NotFound($"Invoices for customer with id {receipt.CustomerId} not found."); + } + + foreach (var invoice in invoices) + { + _logger.LogInformation("Invoice: {Invoice}", JsonConvert.SerializeObject(invoice)); + if (invoice.Posted && invoice.TotalAllocatedAmount < invoice.Amount) + { + model.AllocationLines.Add(new Models.Sales.AllocationLine() + { + InvoiceId = invoice.Id, + Amount = invoice.Amount, + AllocatedAmount = invoice.TotalAllocatedAmount + }); + } + else { - InvoiceId = invoice.Id, - Amount = invoice.Amount, - AllocatedAmount = invoice.TotalAllocatedAmount - }); + _logger.LogInformation("Invoice excluded: Posted={Posted}, TotalAllocatedAmount={TotalAllocatedAmount}, Amount={Amount}", + invoice.Posted, invoice.TotalAllocatedAmount, invoice.Amount); + } } - } - return View(model); + return View(model); + } + catch (Exception ex) + { + _logger.LogError(ex, "An error occurred while processing the Allocate action for id: {id}", id); + return StatusCode(500, "An error occurred while processing your request."); + } } [HttpPost] @@ -256,7 +540,8 @@ public IActionResult Allocate(Models.Sales.Allocate model) { if (ModelState.IsValid) { - if (model.IsValid()) { + if (model.IsValid()) + { var serialize = Newtonsoft.Json.JsonConvert.SerializeObject(model); var content = new StringContent(serialize); content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json"); @@ -288,5 +573,22 @@ public IActionResult SalesInvoicePdf(int id) salesInvoiceModel.SalesInvoiceLines = invoice.SalesInvoiceLines; return View(salesInvoiceModel); } + + public async Task DeleteSalesInvoice(int id) + { + using (var client = new HttpClient()) + { + var baseUri = _configuration!["ApiUrl"]; + client.BaseAddress = new System.Uri(baseUri!); + client.DefaultRequestHeaders.Accept.Clear(); + var response = await client.DeleteAsync(baseUri + "Sales/DeleteSalesInvoice?id=" + id); + + if (response.IsSuccessStatusCode) + return RedirectToAction("SalesInvoices"); + } + + return RedirectToAction("SalesInvoices"); + } + } } diff --git a/src/AccountGoWeb/Controllers/TaxController.cs b/src/AccountGoWeb/Controllers/TaxController.cs index bbc4e9132..4fd7b9a42 100644 --- a/src/AccountGoWeb/Controllers/TaxController.cs +++ b/src/AccountGoWeb/Controllers/TaxController.cs @@ -1,43 +1,182 @@ -using Microsoft.AspNetCore.Mvc; +using AccountGoWeb.Models.TaxSystem; +using AutoMapper; +using Dto.TaxSystem; +using Microsoft.AspNetCore.Mvc; +using System; namespace AccountGoWeb.Controllers { - [Microsoft.AspNetCore.Authorization.Authorize] + //[Microsoft.AspNetCore.Authorization.Authorize] public class TaxController : BaseController { - public TaxController(Microsoft.Extensions.Configuration.IConfiguration config) + private readonly IMapper _mapper; + + public TaxController(Microsoft.Extensions.Configuration.IConfiguration config, IMapper mapper) { _baseConfig = config; + _mapper = mapper; } - public IActionResult Index() { + public IActionResult Index() + { return RedirectToAction("taxes"); } - public async System.Threading.Tasks.Task Taxes() + public async Task Taxes() { ViewBag.PageContentHeader = "Tax"; using (var client = new System.Net.Http.HttpClient()) { - var baseUri = _baseConfig["ApiUrl"]; - client.BaseAddress = new System.Uri(baseUri); + var baseUri = _baseConfig!["ApiUrl"]; + client.BaseAddress = new System.Uri(baseUri!); client.DefaultRequestHeaders.Accept.Clear(); var response = await client.GetAsync(baseUri + "tax/taxes"); if (response.IsSuccessStatusCode) { var responseJson = await response.Content.ReadAsStringAsync(); - var taxSystemDto = Newtonsoft.Json.JsonConvert.DeserializeObject(responseJson); - var taxSystemViewModel = new Models.TaxSystem.TaxSystemViewModel(); - taxSystemViewModel.Taxes = taxSystemDto.Taxes; - taxSystemViewModel.ItemTaxGroups = taxSystemDto.ItemTaxGroups; - taxSystemViewModel.TaxGroups = taxSystemDto.TaxGroups; + var taxSystemDto = Newtonsoft.Json.JsonConvert.DeserializeObject(responseJson); + var taxSystemViewModel = _mapper.Map(taxSystemDto); + return View(taxSystemViewModel); } } return View(); } + + public IActionResult AddNewTax() + { + ViewBag.PageContentHeader = "Add New Tax"; + + @ViewBag.TaxGroups = Models.SelectListItemHelper.TaxGroups(); + @ViewBag.ItemTaxGroups = Models.SelectListItemHelper.ItemTaxGroups(); + + return View(); + } + + [HttpPost] + public IActionResult AddNewTax(TaxForCreation taxForCreationDto) + { + if (ModelState.IsValid) + { + var serialize = Newtonsoft.Json.JsonConvert.SerializeObject(taxForCreationDto); + var content = new StringContent(serialize); + content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json"); + + var response = Post("Tax/addnewtax", content); + if (response.IsSuccessStatusCode) + return RedirectToAction("Taxes"); + } + + @ViewBag.TaxGroups = Models.SelectListItemHelper.TaxGroups(); + @ViewBag.ItemTaxGroups = Models.SelectListItemHelper.ItemTaxGroups(); + + return View(); + } + + public IActionResult EditTax(string tax, string taxGroup, string itemTaxGroup) + { + ViewBag.PageContentHeader = "Edit Tax"; + + // Mapping Dto to View Model + var taxObj = Newtonsoft.Json.JsonConvert.DeserializeObject(tax); + var taxGroupObj = Newtonsoft.Json.JsonConvert.DeserializeObject(taxGroup); + var itemTaxGroupObj = Newtonsoft.Json.JsonConvert.DeserializeObject(itemTaxGroup); + + var editTaxViewModel = new Models.TaxSystem.EditTaxViewModel(); + editTaxViewModel.Tax = _mapper.Map(taxObj); + editTaxViewModel.TaxGroup = _mapper.Map(taxGroupObj); + editTaxViewModel.ItemTaxGroup = _mapper.Map(itemTaxGroupObj); + + @ViewBag.TaxGroups = Models.SelectListItemHelper.TaxGroups(); + @ViewBag.ItemTaxGroups = Models.SelectListItemHelper.ItemTaxGroups(); + + return View(editTaxViewModel); + } + + [HttpPost] + public async Task EditTax(EditTaxViewModel editTaxViewModel) + { + if (ModelState.IsValid) + { + var taxForUpdateDto = _mapper.Map(editTaxViewModel); + + using (var client = new System.Net.Http.HttpClient()) + { + var baseUri = _baseConfig!["ApiUrl"]; + client.BaseAddress = new System.Uri(baseUri!); + client.DefaultRequestHeaders.Accept.Clear(); + + var serialize = Newtonsoft.Json.JsonConvert.SerializeObject(taxForUpdateDto); + var content = new StringContent(serialize); + content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json"); + + var response = await client.PutAsync(baseUri + "Tax/edittax", content); + + if (response.IsSuccessStatusCode) + { + return RedirectToAction("Taxes"); + } + } + + return RedirectToAction("Taxes"); + } + + @ViewBag.TaxGroups = Models.SelectListItemHelper.TaxGroups(); + @ViewBag.ItemTaxGroups = Models.SelectListItemHelper.ItemTaxGroups(); + + return View(editTaxViewModel); + } + + public async Task DeleteTax(int id) + { + using (var client = new HttpClient()) + { + var baseUri = _baseConfig!["ApiUrl"]; + client.BaseAddress = new System.Uri(baseUri!); + client.DefaultRequestHeaders.Accept.Clear(); + var response = await client.DeleteAsync(baseUri + "Tax/deletetax?id=" + id); + + if(response.IsSuccessStatusCode) + return RedirectToAction("Taxes"); + } + + return RedirectToAction("Taxes"); + } + + public async Task DeleteTaxGroup(int id) + { + using (var client = new HttpClient()) + { + var baseUri = _baseConfig!["ApiUrl"]; + client.BaseAddress = new System.Uri(baseUri!); + client.DefaultRequestHeaders.Accept.Clear(); + var response = await client.DeleteAsync(baseUri + "Tax/deletetaxgroup?id=" + id); + + if (response.IsSuccessStatusCode) + return RedirectToAction("Taxes"); + } + + return RedirectToAction("Taxes"); + } + + public async Task DeleteItemTaxGroup(int id) + { + using (var client = new HttpClient()) + { + var baseUri = _baseConfig!["ApiUrl"]; + client.BaseAddress = new System.Uri(baseUri!); + client.DefaultRequestHeaders.Accept.Clear(); + var response = await client.DeleteAsync(baseUri + "Tax/deleteitemtaxgroup?id=" + id); + + if (response.IsSuccessStatusCode) + return RedirectToAction("Taxes"); + } + + return RedirectToAction("Taxes"); + } + } } diff --git a/src/AccountGoWeb/MappingProfile.cs b/src/AccountGoWeb/MappingProfile.cs new file mode 100644 index 000000000..86e45f5c1 --- /dev/null +++ b/src/AccountGoWeb/MappingProfile.cs @@ -0,0 +1,58 @@ +using AutoMapper; + +namespace AccountGoWeb +{ + public class MappingProfile : Profile + { + public MappingProfile() + { + CreateMap(); + CreateMap(); + + #region TaxSystem + + // TaxView Model + CreateMap().ReverseMap(); + CreateMap().ReverseMap(); + CreateMap() + .ForMember(dest => dest.Taxes, opt => opt.MapFrom((src, dest, i, context) => + { + return context.Mapper.Map>(src.Taxes); + })) + .ReverseMap(); + CreateMap().ReverseMap(); + CreateMap() + .ForMember(dest => dest.Taxes, opt => opt.MapFrom((src, dest, i, context) => + { + return context.Mapper.Map>(src.Taxes); + })) + .ReverseMap(); + CreateMap() + .ForMember(dest => dest.Tax, opt => opt.MapFrom((src, dest, i, context) => + { + return context.Mapper.Map(src.Tax); + })) + .ReverseMap(); + + // TaxSystemViewModel + CreateMap() + .ForMember(dest => dest.Taxes, opt => opt.MapFrom((src, dest, i, context) => + { + return context.Mapper.Map>(src.Taxes); + })) + .ForMember(dest => dest.TaxGroups, opt => opt.MapFrom((src, dest, i, context) => + { + return context.Mapper.Map>(src.TaxGroups); + })) + .ForMember(dest => dest.ItemTaxGroups, opt => opt.MapFrom((src, dest, i, context) => + { + return context.Mapper.Map>(src.ItemTaxGroups); + }) + ) + .ReverseMap(); + + #endregion + + } + } +} diff --git a/src/AccountGoWeb/Models/Account/LoginViewModel.cs b/src/AccountGoWeb/Models/Account/LoginViewModel.cs index 2506b0433..418ef2eaa 100644 --- a/src/AccountGoWeb/Models/Account/LoginViewModel.cs +++ b/src/AccountGoWeb/Models/Account/LoginViewModel.cs @@ -1,18 +1,17 @@ using System.ComponentModel.DataAnnotations; -namespace AccountGoWeb.Models.Account +namespace AccountGoWeb.Models.Account; + +public class LoginViewModel { - public class LoginViewModel - { - [Required] - [EmailAddress] - public string Email { get; set; } + [Required] + [EmailAddress] + public string? Email { get; set; } - [Required] - [DataType(DataType.Password)] - public string Password { get; set; } + [Required] + [DataType(DataType.Password)] + public string? Password { get; set; } - [Display(Name = "Remember me?")] - public bool RememberMe { get; set; } - } + [Display(Name = "Remember me?")] + public bool RememberMe { get; set; } } diff --git a/src/AccountGoWeb/Models/Account/RegisterViewModel.cs b/src/AccountGoWeb/Models/Account/RegisterViewModel.cs index b072ae25e..5fbd58e5f 100644 --- a/src/AccountGoWeb/Models/Account/RegisterViewModel.cs +++ b/src/AccountGoWeb/Models/Account/RegisterViewModel.cs @@ -1,29 +1,28 @@ using System.ComponentModel.DataAnnotations; -namespace AccountGoWeb.Models.Account +namespace AccountGoWeb.Models.Account; + +public class RegisterViewModel { - public class RegisterViewModel - { - [Required] - [EmailAddress] - [Display(Name = "Email")] - public string Email { get; set; } + [Required] + [EmailAddress] + [Display(Name = "Email")] + public string? Email { get; set; } - [Required] - [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)] - [DataType(DataType.Password)] - [Display(Name = "Password")] - public string Password { get; set; } + [Required] + [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)] + [DataType(DataType.Password)] + [Display(Name = "Password")] + public string? Password { get; set; } - [DataType(DataType.Password)] - [Display(Name = "Confirm password")] - [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")] - public string ConfirmPassword { get; set; } + [DataType(DataType.Password)] + [Display(Name = "Confirm password")] + [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")] + public string? ConfirmPassword { get; set; } - [Display(Name = "First Name")] - public string FirstName { get; set; } + [Display(Name = "First Name")] + public string? FirstName { get; set; } - [Display(Name = "Last Name")] - public string LastName { get; set; } - } + [Display(Name = "Last Name")] + public string? LastName { get; set; } } diff --git a/src/AccountGoWeb/Models/Bogus/Student.cs b/src/AccountGoWeb/Models/Bogus/Student.cs new file mode 100644 index 000000000..cd50037d1 --- /dev/null +++ b/src/AccountGoWeb/Models/Bogus/Student.cs @@ -0,0 +1,62 @@ +namespace AccountGoWeb.Models.Bogus; + +public class Student +{ + required public int? Id { get; set; } + required public string FirstName { get; set; } + required public string LastName { get; set; } + required public string School { get; set; } + public static IQueryable GetStudents() + { + int ndx = 0; + List students = new List() { + new Student() { Id = ++ndx, FirstName="Max", LastName="Pao", School="Science" }, + new Student() { Id = ++ndx, FirstName="Tom", LastName="Fay", School="Mining" }, + new Student() { Id = ++ndx, FirstName="Ann", LastName="Sun", School="Nursing" }, + new Student() { Id = ++ndx, FirstName="Joe", LastName="Fox", School="Computing" }, + new Student() { Id = ++ndx, FirstName="Sue", LastName="Mai", School="Mining" }, + new Student() { Id = ++ndx, FirstName="Ben", LastName="Lau", School="Business" }, + new Student() { Id = ++ndx, FirstName="Zoe", LastName="Ray", School="Mining" }, + new Student() { Id = ++ndx, FirstName="Sam", LastName="Ash", School="Medicine" }, + new Student() { Id = ++ndx, FirstName="Dan", LastName="Lee", School="Computing" }, + new Student() { Id = ++ndx, FirstName="Pat", LastName="Day", School="Science" }, + new Student() { Id = ++ndx, FirstName="Kim", LastName="Rex", School="Computing" }, + new Student() { Id = ++ndx, FirstName="Tim", LastName="Ram", School="Business" }, + new Student() { Id = ++ndx, FirstName="Rob", LastName="Wei", School="Mining" }, + new Student() { Id = ++ndx, FirstName="Jan", LastName="Tex", School="Science" }, + new Student() { Id = ++ndx, FirstName="Jim", LastName="Kid", School="Business" }, + new Student() { Id = ++ndx, FirstName="Ben", LastName="Chu", School="Medicine" }, + new Student() { Id = ++ndx, FirstName="Mia", LastName="Tao", School="Computing" }, + new Student() { Id = ++ndx, FirstName="Ted", LastName="Day", School="Business" }, + new Student() { Id = ++ndx, FirstName="Amy", LastName="Roy", School="Science" }, + new Student() { Id = ++ndx, FirstName="Ian", LastName="Kit", School="Nursing" }, + new Student() { Id = ++ndx, FirstName="Liz", LastName="Tan", School="Medicine" }, + new Student() { Id = ++ndx, FirstName="Mat", LastName="Roy", School="Tourism" }, + new Student() { Id = ++ndx, FirstName="Deb", LastName="Luo", School="Medicine" }, + new Student() { Id = ++ndx, FirstName="Ana", LastName="Poe", School="Computing" }, + new Student() { Id = ++ndx, FirstName="Lyn", LastName="Raj", School="Science" }, + new Student() { Id = ++ndx, FirstName="Amy", LastName="Ash", School="Tourism" }, + new Student() { Id = ++ndx, FirstName="Kim", LastName="Kid", School="Mining" }, + new Student() { Id = ++ndx, FirstName="Bec", LastName="Fry", School="Nursing" }, + new Student() { Id = ++ndx, FirstName="Eva", LastName="Lap", School="Computing" }, + new Student() { Id = ++ndx, FirstName="Eli", LastName="Yim", School="Business" }, + new Student() { Id = ++ndx, FirstName="Sam", LastName="Hui", School="Science" }, + new Student() { Id = ++ndx, FirstName="Joe", LastName="Jin", School="Mining" }, + new Student() { Id = ++ndx, FirstName="Liz", LastName="Kuo", School="Agriculture" }, + new Student() { Id = ++ndx, FirstName="Ric", LastName="Mak", School="Tourism" }, + new Student() { Id = ++ndx, FirstName="Pam", LastName="Day", School="Computing" }, + new Student() { Id = ++ndx, FirstName="Stu", LastName="Gad", School="Business" }, + new Student() { Id = ++ndx, FirstName="Tom", LastName="Bee", School="Tourism" }, + new Student() { Id = ++ndx, FirstName="Bob", LastName="Lam", School="Agriculture" }, + new Student() { Id = ++ndx, FirstName="Jim", LastName="Ots", School="Medicine" }, + new Student() { Id = ++ndx, FirstName="Tom", LastName="Mag", School="Mining" }, + new Student() { Id = ++ndx, FirstName="Hal", LastName="Doe", School="Agriculture" }, + new Student() { Id = ++ndx, FirstName="Roy", LastName="Kim", School="Nursing" }, + new Student() { Id = ++ndx, FirstName="Vis", LastName="Cox", School="Science" }, + new Student() { Id = ++ndx, FirstName="Kay", LastName="Aga", School="Tourism" }, + new Student() { Id = ++ndx, FirstName="Reo", LastName="Hui", School="Business" }, + new Student() { Id = ++ndx, FirstName="Bob", LastName="Roe", School="Medicine" }, + }; + return students.AsQueryable(); + } +} diff --git a/src/AccountGoWeb/Models/Financial/AccountViewModel.cs b/src/AccountGoWeb/Models/Financial/AccountViewModel.cs new file mode 100644 index 000000000..604595389 --- /dev/null +++ b/src/AccountGoWeb/Models/Financial/AccountViewModel.cs @@ -0,0 +1,13 @@ +namespace AccountGoWeb.Models.Financial +{ + public class AccountViewModel + { + public string? AccountCode { get; set; } + public string? AccountName { get; set; } + public decimal TotalBalance { get; set; } + public decimal TotalDebitBalance { get; set; } + public decimal TotalCreditBalance { get; set; } + public IList? ChildAccounts { get; set; } + + } +} diff --git a/src/AccountGoWeb/Models/Financial/GeneralLedgerSetting.cs b/src/AccountGoWeb/Models/Financial/GeneralLedgerSetting.cs index 866794e6d..a947408b8 100644 --- a/src/AccountGoWeb/Models/Financial/GeneralLedgerSetting.cs +++ b/src/AccountGoWeb/Models/Financial/GeneralLedgerSetting.cs @@ -1,14 +1,13 @@ -namespace AccountGoWeb.Models.Financial +namespace AccountGoWeb.Models.Financial; + +public class GeneralLedgerSetting { - public class GeneralLedgerSetting - { - public int Id { get; set; } - public int? CompanyId { get; set; } - public string CompanyCode { get; set; } - public int? PayableAccountId { get; set; } - public int? PurchaseDiscountAccountId { get; set; } - public int? GoodsReceiptNoteClearingAccountId { get; set; } - public int? SalesDiscountAccountId { get; set; } - public int? ShippingChargeAccountId { get; set; } - } + public int Id { get; set; } + public int? CompanyId { get; set; } + public string? CompanyCode { get; set; } + public int? PayableAccountId { get; set; } + public int? PurchaseDiscountAccountId { get; set; } + public int? GoodsReceiptNoteClearingAccountId { get; set; } + public int? SalesDiscountAccountId { get; set; } + public int? ShippingChargeAccountId { get; set; } } diff --git a/src/AccountGoWeb/Models/FinancialReports.cs b/src/AccountGoWeb/Models/FinancialReports.cs index 7e755e404..8c34a7d9e 100644 --- a/src/AccountGoWeb/Models/FinancialReports.cs +++ b/src/AccountGoWeb/Models/FinancialReports.cs @@ -1,53 +1,42 @@ -//----------------------------------------------------------------------- -// -// Copyright (c) AccountGo. All rights reserved. -// Marvin Perez -// 1/11/2015 9:48:38 AM -// -//----------------------------------------------------------------------- +namespace AccountGoWeb.Models; -using System; - -namespace AccountGoWeb.Models +public class TrialBalance { - public class TrialBalance - { - public int AccountId { get; set; } - public string AccountCode { get; set; } - public string AccountName { get; set; } - public decimal Debit { get; set; } - public decimal Credit { get; set; } - } + public int AccountId { get; set; } + public string? AccountCode { get; set; } + public string? AccountName { get; set; } + public decimal Debit { get; set; } + public decimal Credit { get; set; } +} - public class BalanceSheet - { - public int AccountId { get; set; } - public int AccountClassId { get; set; } - public string AccountCode { get; set; } - public string AccountName { get; set; } - public decimal Amount { get; set; } - } +public class BalanceSheet +{ + public int AccountId { get; set; } + public int AccountClassId { get; set; } + public string? AccountCode { get; set; } + public string? AccountName { get; set; } + public decimal Amount { get; set; } +} - public class IncomeStatement - { - public int AccountId { get; set; } - public bool IsExpense { get; set; } - public string AccountCode { get; set; } - public string AccountName { get; set; } - public decimal Amount { get; set; } - } +public class IncomeStatement +{ + public int AccountId { get; set; } + public bool IsExpense { get; set; } + public string? AccountCode { get; set; } + public string? AccountName { get; set; } + public decimal Amount { get; set; } +} - public partial class MasterGeneralLedger - { - public int Id { get; set; } - public int AccountId { get; set; } - public int CurrencyId { get; set; } - public string DocumentType { get; set; } - public int TransactionNo { get; set; } - public string AccountCode { get; set; } - public string AccountName { get; set; } - public DateTime Date { get; set; } - public decimal Debit { get; set; } - public decimal Credit { get; set; } - } +public partial class MasterGeneralLedger +{ + public int Id { get; set; } + public int AccountId { get; set; } + public int CurrencyId { get; set; } + public string? DocumentType { get; set; } + public int TransactionNo { get; set; } + public string? AccountCode { get; set; } + public string? AccountName { get; set; } + public DateTime Date { get; set; } + public decimal Debit { get; set; } + public decimal Credit { get; set; } } diff --git a/src/AccountGoWeb/Models/ObjectExtensions.cs b/src/AccountGoWeb/Models/ObjectExtensions.cs index 7e3d8c24b..780d99dfb 100644 --- a/src/AccountGoWeb/Models/ObjectExtensions.cs +++ b/src/AccountGoWeb/Models/ObjectExtensions.cs @@ -1,16 +1,14 @@ using Newtonsoft.Json; -using System.IO; -namespace AccountGoWeb.Models +namespace AccountGoWeb.Models; + +public static class ObjectExtensions { - public static class ObjectExtensions + public static string ToJson(this object obj) { - public static string ToJson(this object obj) - { - JsonSerializer js = JsonSerializer.Create(new JsonSerializerSettings()); - var jw = new StringWriter(); - js.Serialize(jw, obj); - return jw.ToString(); - } + JsonSerializer js = JsonSerializer.Create(new JsonSerializerSettings()); + var jw = new StringWriter(); + js.Serialize(jw, obj); + return jw.ToString(); } } diff --git a/src/AccountGoWeb/Models/Purchasing/Payment.cs b/src/AccountGoWeb/Models/Purchasing/Payment.cs index 58c9f230a..16aae98e5 100644 --- a/src/AccountGoWeb/Models/Purchasing/Payment.cs +++ b/src/AccountGoWeb/Models/Purchasing/Payment.cs @@ -1,19 +1,18 @@ -namespace AccountGoWeb.Models.Purchasing +namespace AccountGoWeb.Models.Purchasing; + +public class Payment { - public class Payment - { - public int InvoiceId { get; set; } - public string InvoiceNo { get; set; } - public int VendorId { get; set; } - public string VendorName { get; set; } - public decimal InvoiceAmount { get; set; } - public decimal AmountPaid { get; set; } - public decimal Balance { get { return InvoiceAmount - AmountPaid; } } - [ExpressiveAnnotations.Attributes.AssertThat("AmountToPay <= Balance", ErrorMessage = "Amount to pay cannot be greater than remaining amount to pay.")] - [ExpressiveAnnotations.Attributes.AssertThat("AmountToPay > 0", ErrorMessage = "Amount to pay cannot be zero.")] - public decimal AmountToPay { get; set; } - [System.ComponentModel.DataAnnotations.Required] - public int? AccountId { get; set; } - public System.DateTime Date { get; set; } - } + public int InvoiceId { get; set; } + public string? InvoiceNo { get; set; } + public int VendorId { get; set; } + public string? VendorName { get; set; } + public decimal InvoiceAmount { get; set; } + public decimal AmountPaid { get; set; } + public decimal Balance { get { return InvoiceAmount - AmountPaid; } } + [ExpressiveAnnotations.Attributes.AssertThat("AmountToPay <= Balance", ErrorMessage = "Amount to pay cannot be greater than remaining amount to pay.")] + [ExpressiveAnnotations.Attributes.AssertThat("AmountToPay > 0", ErrorMessage = "Amount to pay cannot be zero.")] + public decimal AmountToPay { get; set; } + [System.ComponentModel.DataAnnotations.Required] + public int? AccountId { get; set; } + public System.DateTime Date { get; set; } } diff --git a/src/AccountGoWeb/Models/Sales/AddSalesReceipt.cs b/src/AccountGoWeb/Models/Sales/AddSalesReceipt.cs index 67f10e309..377a9ecdb 100644 --- a/src/AccountGoWeb/Models/Sales/AddSalesReceipt.cs +++ b/src/AccountGoWeb/Models/Sales/AddSalesReceipt.cs @@ -1,20 +1,19 @@ -namespace AccountGoWeb.Models.Sales +namespace AccountGoWeb.Models.Sales; + +public class AddReceipt { - public class AddReceipt - { - [System.ComponentModel.DataAnnotations.Required] - public int? AccountToDebitId { get; set; } - [System.ComponentModel.DataAnnotations.Required] - public int? AccountToCreditId { get; set; } - [System.ComponentModel.DataAnnotations.Required] - public int? CustomerId { get; set; } - public System.DateTime ReceiptDate {get;set;} - [ExpressiveAnnotations.Attributes.AssertThat("Amount > 0", ErrorMessage = "Amount cannot be zero.")] - public decimal Amount { get; set; } + [System.ComponentModel.DataAnnotations.Required] + public int? AccountToDebitId { get; set; } + [System.ComponentModel.DataAnnotations.Required] + public int? AccountToCreditId { get; set; } + [System.ComponentModel.DataAnnotations.Required] + public int? CustomerId { get; set; } + public System.DateTime ReceiptDate {get;set;} + [ExpressiveAnnotations.Attributes.AssertThat("Amount > 0", ErrorMessage = "Amount cannot be zero.")] + public decimal Amount { get; set; } - public AddReceipt() - { - ReceiptDate = System.DateTime.Now; - } + public AddReceipt() + { + ReceiptDate = System.DateTime.Now; } } diff --git a/src/AccountGoWeb/Models/Sales/Allocate.cs b/src/AccountGoWeb/Models/Sales/Allocate.cs index 78da38d73..704ead295 100644 --- a/src/AccountGoWeb/Models/Sales/Allocate.cs +++ b/src/AccountGoWeb/Models/Sales/Allocate.cs @@ -1,51 +1,48 @@ -using System.Collections.Generic; +namespace AccountGoWeb.Models.Sales; -namespace AccountGoWeb.Models.Sales +public class Allocate { - public class Allocate - { - [System.ComponentModel.DataAnnotations.Required] - public int? CustomerId { get; set; } - [System.ComponentModel.DataAnnotations.Required] - public int? ReceiptId { get; set; } - [System.ComponentModel.DataAnnotations.Required] - public System.DateTime Date { get; set; } - public decimal Amount { get; set; } - public decimal RemainingAmountToAllocate { get; set; } - public decimal SumAllocatedAmount { get { return ComputeSumToAllocateAmount(); } } - public IList AllocationLines { get; set; } - - public Allocate() - { - AllocationLines = new List(); - } + [System.ComponentModel.DataAnnotations.Required] + public int? CustomerId { get; set; } + [System.ComponentModel.DataAnnotations.Required] + public int? ReceiptId { get; set; } + [System.ComponentModel.DataAnnotations.Required] + public System.DateTime Date { get; set; } + public decimal Amount { get; set; } + public decimal RemainingAmountToAllocate { get; set; } + public decimal SumAllocatedAmount { get { return ComputeSumToAllocateAmount(); } } + public IList AllocationLines { get; set; } - private decimal ComputeSumToAllocateAmount() - { - decimal sum = 0; + public Allocate() + { + AllocationLines = new List(); + } - foreach (var line in AllocationLines) { - sum += line.AmountToAllocate.GetValueOrDefault(); - } + private decimal ComputeSumToAllocateAmount() + { + decimal sum = 0; - return sum; + foreach (var line in AllocationLines) { + sum += line.AmountToAllocate.GetValueOrDefault(); } - public bool IsValid() - { - if (RemainingAmountToAllocate < SumAllocatedAmount) - return false; - else - return true; - } + return sum; } - public class AllocationLine + public bool IsValid() { - [System.ComponentModel.DataAnnotations.Required] - public int? InvoiceId { get; set; } - public decimal? Amount { get; set; } - public decimal? AllocatedAmount { get; set; } - public decimal? AmountToAllocate { get; set; } - } + if (RemainingAmountToAllocate < SumAllocatedAmount) + return false; + else + return true; + } } + +public class AllocationLine +{ + [System.ComponentModel.DataAnnotations.Required] + public int? InvoiceId { get; set; } + public decimal? Amount { get; set; } + public decimal? AllocatedAmount { get; set; } + public decimal? AmountToAllocate { get; set; } +} diff --git a/src/AccountGoWeb/Models/Sales/SalesQuotation.cs b/src/AccountGoWeb/Models/Sales/SalesQuotation.cs new file mode 100644 index 000000000..226716fca --- /dev/null +++ b/src/AccountGoWeb/Models/Sales/SalesQuotation.cs @@ -0,0 +1,21 @@ +namespace AccountGoWeb.Models.Sales; +public class SalesQuotations { + [System.ComponentModel.DataAnnotations.Required] + public int CustomerId { get; set; } + [System.ComponentModel.DataAnnotations.Required] + public int PaymentTermId { get; set; } + [System.ComponentModel.DataAnnotations.Required] + public int ItemId { get; set; } + [System.ComponentModel.DataAnnotations.Required] + public int Quantity { get; set; } + [ExpressiveAnnotations.Attributes.AssertThat("Amount > 0", ErrorMessage = "Amount cannot be zero.")] + public decimal Amount { get; set; } + public System.DateTime Date { get; set; } + public decimal Discount { get; set; } + + public SalesQuotations() + { + Date = System.DateTime.Now; + } + +} \ No newline at end of file diff --git a/src/AccountGoWeb/Models/SelectListItemHelper.cs b/src/AccountGoWeb/Models/SelectListItemHelper.cs index 39b6ccf30..2546a4da1 100644 --- a/src/AccountGoWeb/Models/SelectListItemHelper.cs +++ b/src/AccountGoWeb/Models/SelectListItemHelper.cs @@ -1,152 +1,147 @@ -using Microsoft.Extensions.Configuration; -using System.Collections.Generic; -using System.Net.Http; +namespace AccountGoWeb.Models; -namespace AccountGoWeb.Models +public static class SelectListItemHelper { - public static class SelectListItemHelper - { - public static IConfiguration _config; + public static IConfiguration? _config; - public static IEnumerable Accounts() - { - var accounts = GetAsync>("common/postingaccounts").Result; + public static IEnumerable Accounts() + { + var accounts = GetAsync>("common/postingaccounts").Result; - var selectAccounts = new HashSet(); - selectAccounts.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = "", Text = "" }); - foreach (var account in accounts) - selectAccounts.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = account.Id.ToString(), Text = account.AccountName }); + var selectAccounts = new HashSet(); + selectAccounts.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = "", Text = "" }); + foreach (var account in accounts) + selectAccounts.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = account.Id.ToString(), Text = account.AccountName }); - return selectAccounts; - } + return selectAccounts; + } - public static IEnumerable TaxGroups() - { - var taxGroups = GetAsync>("tax/taxgroups").Result; - var selectTaxGroups = new HashSet(); - selectTaxGroups.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = "", Text = "" }); - foreach (var taxGroup in taxGroups) - selectTaxGroups.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = taxGroup.Id.ToString(), Text = taxGroup.Description }); + public static IEnumerable TaxGroups() + { + var taxGroups = GetAsync>("tax/taxgroups").Result; + var selectTaxGroups = new HashSet(); + selectTaxGroups.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = "", Text = "" }); + foreach (var taxGroup in taxGroups) + selectTaxGroups.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = taxGroup.Id.ToString(), Text = taxGroup.Description }); - return selectTaxGroups; - } + return selectTaxGroups; + } - public static IEnumerable ItemTaxGroups() - { - var itemtaxgroups = GetAsync>("tax/itemtaxgroups").Result; - var selectitemtaxgroups = new HashSet(); - selectitemtaxgroups.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = "", Text = "" }); - foreach (var taxGroup in itemtaxgroups) - selectitemtaxgroups.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = taxGroup.Id.ToString(), Text = taxGroup.Name }); + public static IEnumerable ItemTaxGroups() + { + var itemtaxgroups = GetAsync>("tax/itemtaxgroups").Result; + var selectitemtaxgroups = new HashSet(); + selectitemtaxgroups.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = "", Text = "" }); + foreach (var taxGroup in itemtaxgroups) + selectitemtaxgroups.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = taxGroup.Id.ToString(), Text = taxGroup.Name }); - return selectitemtaxgroups; - } + return selectitemtaxgroups; + } - public static IEnumerable PaymentTerms() - { - var paymentTerms = GetAsync>("common/paymentterms").Result; - var selectPaymentTerms = new HashSet(); - selectPaymentTerms.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = "", Text = "" }); - foreach (var term in paymentTerms) - selectPaymentTerms.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = term.Id.ToString(), Text = term.Description }); + public static IEnumerable PaymentTerms() + { + var paymentTerms = GetAsync>("common/paymentterms").Result; + var selectPaymentTerms = new HashSet(); + selectPaymentTerms.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = "", Text = "" }); + foreach (var term in paymentTerms) + selectPaymentTerms.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = term.Id.ToString(), Text = term.Description }); - return selectPaymentTerms; - } + return selectPaymentTerms; + } - public static IEnumerable UnitOfMeasurements() - { - var uoms = GetAsync>("common/measurements").Result; - var selectUOMS = new HashSet(); - selectUOMS.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = "", Text = "" }); - foreach (var item in uoms) - selectUOMS.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = item.Id.ToString(), Text = item.Description }); + public static IEnumerable UnitOfMeasurements() + { + var uoms = GetAsync>("common/measurements").Result; + var selectUOMS = new HashSet(); + selectUOMS.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = "", Text = "" }); + foreach (var item in uoms) + selectUOMS.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = item.Id.ToString(), Text = item.Description }); - return selectUOMS; - } + return selectUOMS; + } - public static IEnumerable ItemCategories() - { - var categories = GetAsync>("common/itemcategories").Result; - var selectCategories = new HashSet(); - selectCategories.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = "", Text = "" }); - foreach (var item in categories) - selectCategories.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = item.Id.ToString(), Text = item.Name }); + public static IEnumerable ItemCategories() + { + var categories = GetAsync>("common/itemcategories").Result; + var selectCategories = new HashSet(); + selectCategories.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = "", Text = "" }); + foreach (var item in categories) + selectCategories.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = item.Id.ToString(), Text = item.Name }); - return selectCategories; - } + return selectCategories; + } - public static IEnumerable CashBanks() - { - var cashBanks = GetAsync>("common/cashbanks").Result; - var selectCashBanks = new HashSet(); - selectCashBanks.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = "", Text = "" }); - foreach (var item in cashBanks) - selectCashBanks.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = item.Id.ToString(), Text = item.Name }); + public static IEnumerable CashBanks() + { + var cashBanks = GetAsync>("common/cashbanks").Result; + var selectCashBanks = new HashSet(); + selectCashBanks.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = "", Text = "" }); + foreach (var item in cashBanks) + selectCashBanks.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = item.Id.ToString(), Text = item.Name }); - return selectCashBanks; - } + return selectCashBanks; + } - public static IEnumerable Customers() - { - var customers = GetAsync>("sales/customers").Result; - var selectCustomers = new HashSet(); - selectCustomers.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = "", Text = "" }); - foreach (var item in customers) - selectCustomers.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = item.Id.ToString(), Text = item.Name }); + public static IEnumerable Customers() + { + var customers = GetAsync>("sales/customers").Result; + var selectCustomers = new HashSet(); + selectCustomers.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = "", Text = "" }); + foreach (var item in customers) + selectCustomers.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = item.Id.ToString(), Text = item.Name }); - return selectCustomers; - } + return selectCustomers; + } - public static IEnumerable Vendors() - { - var vendors = GetAsync>("purchasing/vendors").Result; - var selectVendors = new HashSet(); - selectVendors.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = "", Text = "" }); - foreach (var item in vendors) - selectVendors.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = item.Id.ToString(), Text = item.Name }); + public static IEnumerable Vendors() + { + var vendors = GetAsync>("purchasing/vendors").Result; + var selectVendors = new HashSet(); + selectVendors.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = "", Text = "" }); + foreach (var item in vendors) + selectVendors.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = item.Id.ToString(), Text = item.Name }); - return selectVendors; - } + return selectVendors; + } - public static IEnumerable Items() - { - var items = GetAsync>("inventory/items").Result; - var selectItems = new HashSet(); - selectItems.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = "", Text = "" }); - foreach (var item in items) - selectItems.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = item.Id.ToString(), Text = item.Description }); + public static IEnumerable Items() + { + var items = GetAsync>("inventory/items").Result; + var selectItems = new HashSet(); + selectItems.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = "", Text = "" }); + foreach (var item in items) + selectItems.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = item.Id.ToString(), Text = item.Description }); - return selectItems; - } + return selectItems; + } - public static IEnumerable Measurements() - { - var measurements = GetAsync>("inventory/items").Result; - var selectMeasurements = new HashSet(); - selectMeasurements.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = "", Text = "" }); - foreach (var item in measurements) - selectMeasurements.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = item.Id.ToString(), Text = item.Description }); + public static IEnumerable Measurements() + { + var measurements = GetAsync>("common/measurements").Result; + var selectMeasurements = new HashSet(); + selectMeasurements.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = "", Text = "" }); + foreach (var item in measurements) + selectMeasurements.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = item.Id.ToString(), Text = item.Description }); - return selectMeasurements; - } + return selectMeasurements; + } - #region Private methods - public static async System.Threading.Tasks.Task GetAsync(string uri) + #region Private methods + public static async System.Threading.Tasks.Task GetAsync(string uri) + { + string responseJson = string.Empty; + using (var client = new HttpClient()) { - string responseJson = string.Empty; - using (var client = new HttpClient()) + var baseUri = _config!["ApiUrl"]; + client.BaseAddress = new System.Uri(baseUri!); + client.DefaultRequestHeaders.Accept.Clear(); + var response = await client.GetAsync(baseUri + uri); + if (response.IsSuccessStatusCode) { - var baseUri = _config["ApiUrl"]; - client.BaseAddress = new System.Uri(baseUri); - client.DefaultRequestHeaders.Accept.Clear(); - var response = await client.GetAsync(baseUri + uri); - if (response.IsSuccessStatusCode) - { - responseJson = await response.Content.ReadAsStringAsync(); - } + responseJson = await response.Content.ReadAsStringAsync(); } - return Newtonsoft.Json.JsonConvert.DeserializeObject(responseJson); } - #endregion + return Newtonsoft.Json.JsonConvert.DeserializeObject(responseJson)!; } + #endregion } diff --git a/src/AccountGoWeb/Models/TaxSystem/BaseViewModel.cs b/src/AccountGoWeb/Models/TaxSystem/BaseViewModel.cs new file mode 100644 index 000000000..3164ec6b7 --- /dev/null +++ b/src/AccountGoWeb/Models/TaxSystem/BaseViewModel.cs @@ -0,0 +1,9 @@ +namespace AccountGoWeb.Models.TaxSystem +{ + public abstract class BaseViewModel + { + public virtual int Id { get; set; } + // TODO: Get the user from the logged in user + public string? ModifiedBy { get; set; } + } +} diff --git a/src/AccountGoWeb/Models/TaxSystem/EditTaxViewModel.cs b/src/AccountGoWeb/Models/TaxSystem/EditTaxViewModel.cs new file mode 100644 index 000000000..68aded1b5 --- /dev/null +++ b/src/AccountGoWeb/Models/TaxSystem/EditTaxViewModel.cs @@ -0,0 +1,13 @@ +using System.ComponentModel.DataAnnotations; + +namespace AccountGoWeb.Models.TaxSystem +{ + public class EditTaxViewModel + { + public int SalesAccountId { get; set; } + public int PurchaseAccountId { get; set; } + public Tax? Tax { get; set; } + public TaxGroup? TaxGroup { get; set; } + public ItemTaxGroup? ItemTaxGroup { get; set; } + } +} diff --git a/src/AccountGoWeb/Models/TaxSystem/ItemTaxGroup.cs b/src/AccountGoWeb/Models/TaxSystem/ItemTaxGroup.cs new file mode 100644 index 000000000..a525eb093 --- /dev/null +++ b/src/AccountGoWeb/Models/TaxSystem/ItemTaxGroup.cs @@ -0,0 +1,20 @@ +using System.ComponentModel.DataAnnotations; + +namespace AccountGoWeb.Models.TaxSystem +{ + public class ItemTaxGroup : BaseViewModel + { + [Required(ErrorMessage = "The Tax Group Name field is Required.")] + [StringLength(50)] + public string? Name { get; set; } + + [Display(Name = "Fully Exempt")] + public bool IsFullyExempt { get; set; } + public IList Taxes { get; set; } + + public ItemTaxGroup() + { + Taxes = new List(); + } + } +} diff --git a/src/AccountGoWeb/Models/TaxSystem/ItemTaxGroupTax.cs b/src/AccountGoWeb/Models/TaxSystem/ItemTaxGroupTax.cs new file mode 100644 index 000000000..8ed90b741 --- /dev/null +++ b/src/AccountGoWeb/Models/TaxSystem/ItemTaxGroupTax.cs @@ -0,0 +1,9 @@ +namespace AccountGoWeb.Models.TaxSystem +{ + public class ItemTaxGroupTax + { + public int TaxId { get; set; } + public int ItemTaxGroupId { get; set; } + public bool IsExempt { get; set; } + } +} diff --git a/src/AccountGoWeb/Models/TaxSystem/Tax.cs b/src/AccountGoWeb/Models/TaxSystem/Tax.cs new file mode 100644 index 000000000..644a6af0c --- /dev/null +++ b/src/AccountGoWeb/Models/TaxSystem/Tax.cs @@ -0,0 +1,20 @@ +using System.ComponentModel.DataAnnotations; + +namespace AccountGoWeb.Models.TaxSystem +{ + public class Tax : BaseViewModel + { + [Required(ErrorMessage = "The Tax Name field is Required.")] + [StringLength(50)] + public string? TaxName { get; set; } + + [Required(ErrorMessage = "The Tax Code field is Required.")] + [StringLength(16)] + public string? TaxCode { get; set; } + + [Range(0, 100, ErrorMessage = "The Rate field must be between 0 and 100.")] + public decimal Rate { get; set; } + + public bool IsActive { get; set; } + } +} diff --git a/src/AccountGoWeb/Models/TaxSystem/TaxGroup.cs b/src/AccountGoWeb/Models/TaxSystem/TaxGroup.cs new file mode 100644 index 000000000..eae959112 --- /dev/null +++ b/src/AccountGoWeb/Models/TaxSystem/TaxGroup.cs @@ -0,0 +1,20 @@ +using System.ComponentModel.DataAnnotations; + +namespace AccountGoWeb.Models.TaxSystem +{ + public class TaxGroup : BaseViewModel + { + [Required(ErrorMessage = "The Tax Group Name field is Required.")] + [StringLength(50)] + public string? Description { get; set; } + public bool TaxAppliedToShipping { get; set; } + public bool IsActive { get; set; } + + public IList Taxes { get; set; } + + public TaxGroup() + { + Taxes = new List(); + } + } +} diff --git a/src/AccountGoWeb/Models/TaxSystem/TaxGroupTax.cs b/src/AccountGoWeb/Models/TaxSystem/TaxGroupTax.cs new file mode 100644 index 000000000..7edf4094c --- /dev/null +++ b/src/AccountGoWeb/Models/TaxSystem/TaxGroupTax.cs @@ -0,0 +1,8 @@ +namespace AccountGoWeb.Models.TaxSystem +{ + public class TaxGroupTax + { + public int TaxId { get; set; } + public int TaxGroupId { get; set; } + } +} diff --git a/src/AccountGoWeb/Models/TaxSystem/TaxSystemViewModel.cs b/src/AccountGoWeb/Models/TaxSystem/TaxSystemViewModel.cs index 23f09a05d..46a4fcbbf 100644 --- a/src/AccountGoWeb/Models/TaxSystem/TaxSystemViewModel.cs +++ b/src/AccountGoWeb/Models/TaxSystem/TaxSystemViewModel.cs @@ -1,11 +1,9 @@ using Dto.TaxSystem; -namespace AccountGoWeb.Models.TaxSystem +namespace AccountGoWeb.Models.TaxSystem; +public class TaxSystemViewModel { - public class TaxSystemViewModel - { - public System.Collections.Generic.IEnumerable Taxes { get; set; } - public System.Collections.Generic.IEnumerable TaxGroups { get; set; } - public System.Collections.Generic.IEnumerable ItemTaxGroups { get; set; } - } + public System.Collections.Generic.IEnumerable? Taxes { get; set; } + public System.Collections.Generic.IEnumerable? TaxGroups { get; set; } + public System.Collections.Generic.IEnumerable? ItemTaxGroups { get; set; } } diff --git a/src/AccountGoWeb/Program.cs b/src/AccountGoWeb/Program.cs index 79f367cc5..f75e21924 100644 --- a/src/AccountGoWeb/Program.cs +++ b/src/AccountGoWeb/Program.cs @@ -1,26 +1,53 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; - -namespace AccountGoWeb +using AccountGoWeb.Components; +using Microsoft.AspNetCore.Authentication.Cookies; + +var builder = WebApplication.CreateBuilder(args); + +builder.AddServiceDefaults(); + +// Mapping +builder.Services.AddAutoMapper(typeof(Program)); + +builder.Services.AddControllersWithViews(); + +string apiurl = System.Environment.GetEnvironmentVariable("APIURL") ?? "http://localhost:8001/api/"; + +builder.Configuration["ApiUrl"] = apiurl; +Console.WriteLine($"[ASPNETCORE SERVER] API URL {builder.Configuration["ApiUrl"]}"); + +builder.Services.AddHttpClient(); +builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) + .AddCookie(o => o.LoginPath = new PathString("/account/signin")); + +builder.Services + .AddRazorComponents() + .AddInteractiveServerComponents() + .AddCircuitOptions(options => options.DetailedErrors = true); // for debugging razor components + +var app = builder.Build(); + +// Configure the HTTP request pipeline. +if (!app.Environment.IsDevelopment()) { - public class Program - { - public static void Main(string[] args) - { - CreateHostBuilder(args).Build().Run(); - } - - public static IHostBuilder CreateHostBuilder(string[] args) => - Host.CreateDefaultBuilder(args) - .ConfigureWebHostDefaults(webBuilder => - { - webBuilder.UseStartup(); - }); - } + 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.UseAuthentication(); +app.UseAntiforgery(); +app.UseAuthorization(); + +app.MapControllerRoute( + name: "default", + pattern: "{controller=Home}/{action=Index}/{id?}"); + +app.MapRazorComponents() + .AddInteractiveServerRenderMode(); + +app.Run(); diff --git a/src/AccountGoWeb/Properties/launchSettings.json b/src/AccountGoWeb/Properties/launchSettings.json index 0c2a63276..684f35562 100644 --- a/src/AccountGoWeb/Properties/launchSettings.json +++ b/src/AccountGoWeb/Properties/launchSettings.json @@ -13,9 +13,9 @@ "launchBrowser": true, "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" - } - }, - "AccountGoWeb": { + } + }, + "AccountGoWeb": { "commandName": "Project", "launchBrowser": true, "environmentVariables": { diff --git a/src/AccountGoWeb/Resource.Designer.cs b/src/AccountGoWeb/Resource.Designer.cs index 2267688fc..4fa30fbab 100644 --- a/src/AccountGoWeb/Resource.Designer.cs +++ b/src/AccountGoWeb/Resource.Designer.cs @@ -8,55 +8,54 @@ // //------------------------------------------------------------------------------ -namespace AccountGoWeb { - using System; - using System.Reflection; +namespace AccountGoWeb; + +using System.Reflection; + + +/// +/// A strongly-typed resource class, for looking up localized strings, etc. +/// +// This class was auto-generated by the StronglyTypedResourceBuilder +// class via a tool like ResGen or Visual Studio. +// To add or remove a member, edit your .ResX file then rerun ResGen +// with the /str option, or rebuild your VS project. +[global::System.Diagnostics.DebuggerNonUserCodeAttribute()] +[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] +public class Resource { + + private static global::System.Resources.ResourceManager resourceMan; + private static global::System.Globalization.CultureInfo resourceCulture; + + internal Resource() { + } /// - /// A strongly-typed resource class, for looking up localized strings, etc. + /// Returns the cached ResourceManager instance used by this class. /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - public class Resource { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - internal Resource() { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("AccountGoWeb.Resource", typeof(Resource).GetTypeInfo().Assembly); - resourceMan = temp; - } - return resourceMan; + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("AccountGoWeb.Resource", typeof(Resource).GetTypeInfo().Assembly); + resourceMan = temp; } + return resourceMan; } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - public static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; } } } diff --git a/src/AccountGoWeb/Scripts/Home/Index.tsx b/src/AccountGoWeb/Scripts/Home/Index.tsx deleted file mode 100644 index 997e4a6c0..000000000 --- a/src/AccountGoWeb/Scripts/Home/Index.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import * as React from "react"; -import * as ReactDOM from "react-dom"; - -interface IHomeProps { - pageTitle: string; -} - -class Home extends React.Component { - render() { - return ( -
- Tiles or widgets here! -
- ); - } -} - -ReactDOM.render( - , - document.getElementById("home") -); - -export default Home; \ No newline at end of file diff --git a/src/AccountGoWeb/Scripts/Quotations/SalesQuotation.tsx b/src/AccountGoWeb/Scripts/Quotations/SalesQuotation.tsx deleted file mode 100644 index 5bd89650c..000000000 --- a/src/AccountGoWeb/Scripts/Quotations/SalesQuotation.tsx +++ /dev/null @@ -1,403 +0,0 @@ -import * as React from "react"; -import * as ReactDOM from "react-dom"; -import {observer} from "mobx-react"; -import * as d3 from "d3"; -import {autorun, observable} from 'mobx'; -import * as accounting from "accounting"; - -import SelectCustomer from "../Shared/Components/SelectCustomer"; -import SelectPaymentTerm from "../Shared/Components/SelectPaymentTerm"; -import SelectLineItem from "../Shared/Components/SelectLineItem"; -import SelectLineMeasurement from "../Shared/Components/SelectLineMeasurement"; - -import SalesQuotationLine from "../Shared/Stores/Quotations/SalesQuotationLine"; -import SalesQuotationStore from "../Shared/Stores/Quotations/SalesQuotationStore"; - - -let quotationId = window.location.search.split("?id=")[1]; - -let store = new SalesQuotationStore(quotationId); - -@observer -class ValidationErrors extends React.Component{ - render() { - - if (store.validationErrors !== undefined && store.validationErrors.length > 0) { - var errors = []; - store.validationErrors.map(function (item, index) { - errors.push(
  • {item}
  • ); - }); - return ( -
    -
      - {errors} -
    -
    - - ); - } - return null; - } -} - -@observer -class SaveQuotationButton extends React.Component{ - saveNewSalesQuotation(e) { - store.saveNewQuotation(); - } - //className = {!store.salesInvoice.posted && store.editMode - render() { - return ( - - ); - } -} - -class CancelQuotationButton extends React.Component{ - cancelOnClick() { - let baseUrl = location.protocol - + "//" + location.hostname - + (location.port && ":" + location.port) - + "/"; - - window.location.href = baseUrl + 'quotations'; - } - - render() { - return ( - - ); - } -} - -@observer -class SalesQuotationHeader extends React.Component{ - onChangeQuotationDate(e) { - store.changedQuotationDate(e.target.value); - } - - - - onChangeCustomer(e) { - alert(''); - } - - onChangeReferenceNo(e) { - store.changedReferenceNo(e.target.value); - } - - - render() { - return ( -
    -
    - Customer Information - {store.salesQuotation.customerId} -
    -
    -
    -
    -
    Customer
    -
    -
    -
    -
    Payment Term
    -
    -
    -
    -
    -
    -
    Date
    -
    - -
    -
    -
    Reference no.
    -
    - -
    -
    -
    Status
    -
    - -
    -
    -
    -
    - ); - } -} - -@observer -class SalesQuotationLines extends React.Component{ - - - - addLineItem() { - - if (store.validationLine()) { - - var itemId, measurementId, quantity, amount, discount, code; - itemId = (document.getElementById("optNewItemId") as HTMLInputElement).value; - - measurementId = (document.getElementById("optNewMeasurementId") as HTMLInputElement).value; - quantity = (document.getElementById("txtNewQuantity") as HTMLInputElement).value; - amount = (document.getElementById("txtNewAmount") as HTMLInputElement).value; - discount = (document.getElementById("txtNewDiscount") as HTMLInputElement).value; - code = (document.getElementById("txtNewCode") as HTMLInputElement).value; - //console.log(`itemId: ${itemId} | measurementId: ${measurementId} | quantity: ${quantity} | amount: ${amount} | discount: ${discount}`); - store.addLineItem(0, itemId, measurementId, quantity, amount, discount, code); - - - (document.getElementById("optNewItemId") as HTMLInputElement).value = ""; - (document.getElementById("txtNewCode") as HTMLInputElement).value = ""; - (document.getElementById("optNewMeasurementId") as HTMLInputElement).value = ""; - (document.getElementById("txtNewQuantity") as HTMLInputElement).value = "1"; - (document.getElementById("txtNewAmount") as HTMLInputElement).value = ""; - (document.getElementById("txtNewDiscount") as HTMLInputElement).value = ""; - - } - - } - - onClickRemoveLineItem(i, e) { - store.removeLineItem(i); - } - - onChangeQuantity(e) { - store.updateLineItem(e.target.name, "quantity", e.target.value); - } - - onChangeAmount(e) { - store.updateLineItem(e.target.name, "amount", e.target.value); - } - - onChangeDiscount(e) { - store.updateLineItem(e.target.name, "discount", e.target.value); - } - - onChangeCode(e) { - store.updateLineItem(e.target.name, "code", e.target.value); - } - - - onFocusOutItem(e, isNew, i) { - - var isExisting = false; - for (var x = 0; x < store.commonStore.items.length; x++) { - if (store.commonStore.items[x].code == i.target.value) { - isExisting = true; - if (isNew) { - (document.getElementById("optNewItemId") as HTMLInputElement).value = store.commonStore.items[x].id; - (document.getElementById("optNewMeasurementId") as HTMLInputElement).value = store.commonStore.items[x].sellMeasurementId; - (document.getElementById("txtNewAmount") as HTMLInputElement).value = store.commonStore.items[x].price; - (document.getElementById("txtNewQuantity") as HTMLInputElement).value = "1"; - document.getElementById("txtNewCode").style.borderColor = ""; - } - else { - store.updateLineItem(e, "itemId", store.commonStore.items[x].id); - store.updateLineItem(e, "measurementId", store.commonStore.items[x].sellMeasurementId); - store.updateLineItem(e, "amount", store.commonStore.items[x].price); - store.updateLineItem(e, "quantity", 1); - i.target.style.borderColor = ""; - } - } - } - - if (!isExisting) - - if (isNew) { - (document.getElementById("optNewItemId") as HTMLInputElement).value = ""; - (document.getElementById("optNewMeasurementId") as HTMLInputElement).value = ""; - (document.getElementById("txtNewAmount") as HTMLInputElement).value = ""; - (document.getElementById("txtNewQuantity") as HTMLInputElement).value = ""; - document.getElementById("txtNewCode").style.borderColor = '#FF0000'; - //document.getElementById("txtNewCode").appendChild(span); - // document.getElementById("txtNewCode").style.border = 'solid'; - } - else { - //store.updateLineItem(e, "itemId", ""); - //store.updateLineItem(e, "measurementId", ""); - //store.updateLineItem(e, "amount", ""); - //store.updateLineItem(e, "quantity", ""); - i.target.style.borderColor = "red"; - //i.target.appendChild(span); - // i.target.style.border = "solid"; - - } - - } - - @observable lineNo = 0; - - - render() { - var newLine = 0; - var lineItems = []; - - for (var i = 0; i < store.salesQuotation.salesQuotationLines.length; i++) { - newLine = newLine + 10; - //var initialCode = this.onloadCode(store.salesQuotation.salesQuotationLines[i].itemId); // this is for initial value of code - - - lineItems.push( - - - - - - - - - {store.getLineTotal(i) } - - - - - ); - //autorun(() => this.lineNo = newLine); - } - - return ( -
    -
    - Line Items -
    -
    - - - - - - - - - - - - - - - - {lineItems} - - - - - - - - - - - - -
    NoItemCodeMeasurementQuantityAmountDiscountLine Total
    - -
    -
    -
    - ); - } -} - -@observer -class SalesQuotationTotals extends React.Component{ - render() { - return ( -
    -
    -
    -
    -
    {accounting.formatMoney(store.RTotal, { symbol: "", format: "%s%v" }) }
    -
    -
    {accounting.formatMoney(store.TTotal, { symbol: "", format: "%s%v" }) }
    -
    -
    {accounting.formatMoney(store.GTotal, { symbol: "", format: "%s%v" }) }
    -
    -
    -
    - ); - } -} - -@observer -class BookButton extends React.Component{ - bookOnClick(e) { - store.bookQuotation(); - } - - render() { - return ( - - - ); - } -} - -@observer -class EditButton extends React.Component { - onClickEditButton() { - // Remove " disabledControl" from current className - var nodes = document.getElementById("divSalesQuotationForm").getElementsByTagName('*'); - for (var i = 0; i < nodes.length; i++) { - var subStringLength = nodes[i].className.length - " disabledControl".length; - nodes[i].className = nodes[i].className.substring(0, subStringLength); - } - - store.changedEditMode(true); - } - render() { - return ( - - - Edit - - ); - } - -} - -export default class SalesQuotation extends React.Component { - render() { - return ( -
    -
    - -
    -
    - - - - -
    -
    - - - -
    -
    - ); - } -} - - -ReactDOM.render(, document.getElementById("divSalesQuotation")); - - - \ No newline at end of file diff --git a/src/AccountGoWeb/Scripts/Shared/Stores/AppState.tsx b/src/AccountGoWeb/Scripts/Shared/Stores/AppState.tsx deleted file mode 100644 index 1e237b89f..000000000 --- a/src/AccountGoWeb/Scripts/Shared/Stores/AppState.tsx +++ /dev/null @@ -1,4 +0,0 @@ -import {observable} from 'mobx'; - -export default class AppState { -} \ No newline at end of file diff --git a/src/AccountGoWeb/Scripts/Shared/Stores/Common/CommonStore.tsx b/src/AccountGoWeb/Scripts/Shared/Stores/Common/CommonStore.tsx deleted file mode 100644 index 5b289ee11..000000000 --- a/src/AccountGoWeb/Scripts/Shared/Stores/Common/CommonStore.tsx +++ /dev/null @@ -1,130 +0,0 @@ -import {observable, extendObservable, action} from 'mobx'; -import * as axios from "axios"; - -import Config = require("Config"); - -export default class CommonStore { - @observable customers = []; - @observable paymentTerms = []; - @observable items = []; - @observable measurements = []; - @observable vendors = []; - @observable accounts = []; - @observable salesQuotationStatus = []; - - constructor() { - this.loadCustomersLookup(); - this.loadPaymentTermsLookup(); - this.loadItemsLookup(); - this.loadMeasurementsLookup(); - this.loadVendorsLookup(); - this.loadAccountsLookup(); - this.loadQuotationStatusLookup(); - } - - loadCustomersLookup() { - let customers = this.customers; - axios.get(Config.apiUrl + "common/customers") - .then(function (result) { - const data = result.data; - for (var i = 0; i < Object.keys(data).length; i++) { - customers.push(data[i]); - } - }); - } - - loadPaymentTermsLookup() { - let paymentTerms = this.paymentTerms; - axios.get(Config.apiUrl + "common/paymentterms") - .then(function (result) { - const data = result.data; - for (var i = 0; i < Object.keys(data).length; i++) { - paymentTerms.push(data[i]); - } - }); - } - - loadVendorsLookup() { - let vendors = this.vendors; - axios.get(Config.apiUrl + "common/vendors") - .then(function (result) { - const data = result.data; - for (var i = 0; i < Object.keys(data).length; i++) { - vendors.push(data[i]); - } - }.bind(this)); - } - - loadItemsLookup() { - let items = this.items; - axios.get(Config.apiUrl + "common/items") - .then(function (result) { - const data = result.data; - for (var i = 0; i < Object.keys(data).length; i++) { - items.push(data[i]); - } - }); - } - - loadMeasurementsLookup() { - let measurements = this.measurements; - axios.get(Config.apiUrl + "common/measurements") - .then(function (result) { - const data = result.data; - for (var i = 0; i < Object.keys(data).length; i++) { - measurements.push(data[i]); - } - }); - } - - loadVoucherTypesLookup() { - } - - loadQuotationStatusLookup() { - let quotationStatus = this.salesQuotationStatus; - axios.get(Config.apiUrl + "common/salesquotationstatus") - .then(function (result) { - const data = result.data; - for (var i = 0; i < Object.keys(data).length; i++) - { - quotationStatus.push(data[i]); - } - }) - } - - loadAccountsLookup() { - let accounts = this.accounts; - axios.get(Config.apiUrl + "common/postingaccounts") - .then(function (result) { - const data = result.data; - for (var i = 0; i < Object.keys(data).length; i++) { - accounts.push(data[i]); - } - }); - } - - getApplicableTaxes(itemId: number, partyId: number) { - var result = axios.get(Config.apiUrl + "tax/gettax?itemId=" + itemId + "&partyId=" + partyId); - result.then(function (result) { - return result.data; - }); - } - - getSalesLineTaxAmount(quantity: number, amount: number, discount: number, taxes: any) { - var lineTaxTotal = 0; - amount = (amount * quantity) - discount; - taxes.map(function (tax) { - lineTaxTotal = lineTaxTotal + (amount - (amount / (1 + (tax.rate / 100)))); - }); - return lineTaxTotal; - } - - getPurhcaseLineTaxAmount(quantity: number, amount: number, discount: number, taxes: any) { - var lineTaxTotal = 0; - amount = (amount * quantity) - discount; - taxes.map(function (tax) { - lineTaxTotal = lineTaxTotal + (amount - (amount / (1 + (tax.rate / 100)))); - }); - return lineTaxTotal; - } -} \ No newline at end of file diff --git a/src/AccountGoWeb/Scripts/Shared/Stores/Purchasing/PurchaseInvoice.tsx b/src/AccountGoWeb/Scripts/Shared/Stores/Purchasing/PurchaseInvoice.tsx deleted file mode 100644 index 025b004e8..000000000 --- a/src/AccountGoWeb/Scripts/Shared/Stores/Purchasing/PurchaseInvoice.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import PurchaseInvoiceLine from "./PurchaseInvoiceLine"; - -export default class PurchaseInvoice { - id: number; - fromPurchaseOrderId: number; - vendorId: number; - invoiceDate: Date; - paymentTermId: number; - referenceNo: string; - posted: boolean; - readyForPosting: boolean; - purchaseInvoiceLines: PurchaseInvoiceLine[] = []; - statusId: number; - - constructor() { - this.id = 0; - this.posted = false; - this.readyForPosting = false; - - } -} \ No newline at end of file diff --git a/src/AccountGoWeb/Scripts/Shared/Stores/Purchasing/PurchaseInvoiceLine.tsx b/src/AccountGoWeb/Scripts/Shared/Stores/Purchasing/PurchaseInvoiceLine.tsx deleted file mode 100644 index 52be17a37..000000000 --- a/src/AccountGoWeb/Scripts/Shared/Stores/Purchasing/PurchaseInvoiceLine.tsx +++ /dev/null @@ -1,19 +0,0 @@ -export default class PurchaseInvoiceLine { - id = 0; - itemId; - measurementId; - quantity; - amount; - discount; - remainingQtyToInvoice: number; - - constructor(id, itemId, measurementId, quantity, amount, discount) { - this.id = id; - this.itemId = itemId; - this.measurementId = measurementId; - this.quantity = quantity; - this.amount = amount; - this.discount = discount; - this.remainingQtyToInvoice = quantity; - } -} \ No newline at end of file diff --git a/src/AccountGoWeb/Scripts/Shared/Stores/Purchasing/PurchaseOrder.tsx b/src/AccountGoWeb/Scripts/Shared/Stores/Purchasing/PurchaseOrder.tsx deleted file mode 100644 index b82284b5b..000000000 --- a/src/AccountGoWeb/Scripts/Shared/Stores/Purchasing/PurchaseOrder.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import PurchaseOrderLine from "./PurchaseOrderLine"; - -export default class PurchaseOrder { - id: number; - vendorId: number; - orderDate: Date; - paymentTermId: number; - referenceNo: string; - statusId: number; - purchaseOrderLines: PurchaseOrderLine[] = []; -} \ No newline at end of file diff --git a/src/AccountGoWeb/Scripts/Shared/Stores/Purchasing/PurchaseOrderLine.tsx b/src/AccountGoWeb/Scripts/Shared/Stores/Purchasing/PurchaseOrderLine.tsx deleted file mode 100644 index bd21b5b5f..000000000 --- a/src/AccountGoWeb/Scripts/Shared/Stores/Purchasing/PurchaseOrderLine.tsx +++ /dev/null @@ -1,19 +0,0 @@ -export default class PurchaseOrderLine { - id = 0; - itemId; - measurementId; - quantity; - amount; - discount; - code; - - constructor(id, itemId, measurementId, quantity, amount, discount, code) { - this.id = id; - this.itemId = itemId; - this.measurementId = measurementId; - this.quantity = quantity; - this.amount = amount; - this.discount = discount; - this.code = code; - } -} \ No newline at end of file diff --git a/src/AccountGoWeb/Scripts/Shared/Stores/Quotations/SalesQuotation.tsx b/src/AccountGoWeb/Scripts/Shared/Stores/Quotations/SalesQuotation.tsx deleted file mode 100644 index b692dffdf..000000000 --- a/src/AccountGoWeb/Scripts/Shared/Stores/Quotations/SalesQuotation.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import SalesQuotationLine from "./SalesQuotationLine"; - -export default class SalesQuotation { - id: number; - customerId: number; - quotationDate: Date; - paymentTermId: number; - referenceNo: string; - statusId: number; - salesQuotationLines: SalesQuotationLine[] = []; -} \ No newline at end of file diff --git a/src/AccountGoWeb/Scripts/Shared/Stores/Sales/SalesOrder.tsx b/src/AccountGoWeb/Scripts/Shared/Stores/Sales/SalesOrder.tsx deleted file mode 100644 index 4381b3189..000000000 --- a/src/AccountGoWeb/Scripts/Shared/Stores/Sales/SalesOrder.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import SalesOrderLine from "./SalesOrderLine"; - -//interface ISalesOrder { -// id; -// customerId; -// orderDate; -// paymentTermId; -// referenceNo; -// salesOrderLines: SalesOrderLine[]; -//} - -export default class SalesOrder { - id: number; - customerId: number; - orderDate: Date; - paymentTermId: number; - referenceNo: string; - statusId: number; - quotationId: number; - salesOrderLines: SalesOrderLine[] = []; -} \ No newline at end of file diff --git a/src/AccountGoWeb/Scripts/Shared/Stores/Sales/SalesOrderLine.tsx b/src/AccountGoWeb/Scripts/Shared/Stores/Sales/SalesOrderLine.tsx deleted file mode 100644 index d491ebb40..000000000 --- a/src/AccountGoWeb/Scripts/Shared/Stores/Sales/SalesOrderLine.tsx +++ /dev/null @@ -1,18 +0,0 @@ -export default class SalesOrderLine { - id: number; - itemId: number; - measurementId: number; - quantity: number; - amount: number; - discount: number; - code: number; - constructor(id, itemId, measurementId, quantity, amount, discount, code) { - this.id = id; - this.itemId = itemId; - this.measurementId = measurementId; - this.quantity = quantity; - this.amount = amount; - this.discount = discount; - this.code = code; - } -} \ No newline at end of file diff --git a/src/AccountGoWeb/Scripts/Shared/Stores/TaxSystem/Tax.tsx b/src/AccountGoWeb/Scripts/Shared/Stores/TaxSystem/Tax.tsx deleted file mode 100644 index 08993815f..000000000 --- a/src/AccountGoWeb/Scripts/Shared/Stores/TaxSystem/Tax.tsx +++ /dev/null @@ -1,6 +0,0 @@ -export default class SalesOrder { - id: number; - code: string; - name: string; - rate: number; -} \ No newline at end of file diff --git a/src/AccountGoWeb/Startup.cs b/src/AccountGoWeb/Startup.cs deleted file mode 100644 index d6a8e1e4d..000000000 --- a/src/AccountGoWeb/Startup.cs +++ /dev/null @@ -1,81 +0,0 @@ -using System; -using System.IO; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.HttpsPolicy; -using Microsoft.AspNetCore.Authentication.Cookies; -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Infrastructure.AssemblyLoader; - -namespace AccountGoWeb -{ - public class Startup - { - public Startup(IConfiguration configuration) - { - Configuration = configuration; - // var builder = new ConfigurationBuilder() - // .SetBasePath(env.ContentRootPath) - // .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) - // .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true) - // .AddEnvironmentVariables(); - // Configuration = builder.Build(); - - string urlhost = System.Environment.GetEnvironmentVariable("APIHOST") ?? "localhost"; - Configuration["ApiUrl"] = $"http://{urlhost}:8001/api/"; - System.Console.WriteLine($"[ASPNETCORE SERVER] API URL {Configuration["ApiUrl"]}"); - } - - public IConfiguration Configuration { get; } - - // This method gets called by the runtime. Use this method to add services to the container. - public void ConfigureServices(IServiceCollection services) - { - services.AddControllersWithViews(); - - services.AddSingleton(Configuration); - - services.AddHttpClient(); - - services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) - .AddCookie(o => o.LoginPath = new PathString("/account/signin")); - - } - - // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, IWebHostEnvironment env) - { - if (env.IsDevelopment()) - { - app.UseDeveloperExceptionPage(); - } - else - { - 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.UseAuthentication(); - - app.UseAuthorization(); - - app.UseEndpoints(endpoints => - { - endpoints.MapControllerRoute( - name: "default", - pattern: "{controller=Home}/{action=Index}/{id?}"); - }); - } - } -} diff --git a/src/AccountGoWeb/Views/Account/SignIn.cshtml b/src/AccountGoWeb/Views/Account/SignIn.cshtml index f8493b30c..6afaf4883 100644 --- a/src/AccountGoWeb/Views/Account/SignIn.cshtml +++ b/src/AccountGoWeb/Views/Account/SignIn.cshtml @@ -16,12 +16,12 @@ - - - + + + - +
    @@ -74,11 +74,11 @@
    - - - - - - + + + + + + diff --git a/src/AccountGoWeb/Views/Administration/Company.cshtml b/src/AccountGoWeb/Views/Administration/Company.cshtml index acb4dff48..c3e7bdbb0 100644 --- a/src/AccountGoWeb/Views/Administration/Company.cshtml +++ b/src/AccountGoWeb/Views/Administration/Company.cshtml @@ -12,6 +12,7 @@ }

    + @* *@

    +
    + +
    + + +
    +
    diff --git a/src/AccountGoWeb/Views/Contact/Contact.cshtml b/src/AccountGoWeb/Views/Contact/Contact.cshtml index 197a2dedb..03194cbf3 100644 --- a/src/AccountGoWeb/Views/Contact/Contact.cshtml +++ b/src/AccountGoWeb/Views/Contact/Contact.cshtml @@ -46,12 +46,12 @@ -
    + @*
    Fax
    -
    +
    *@
    Website
    @@ -68,7 +68,7 @@
    - + Close
    diff --git a/src/AccountGoWeb/Views/Dashboard/MonthlySales.cshtml b/src/AccountGoWeb/Views/Dashboard/MonthlySales.cshtml index c94ca011a..e3007bbbc 100644 --- a/src/AccountGoWeb/Views/Dashboard/MonthlySales.cshtml +++ b/src/AccountGoWeb/Views/Dashboard/MonthlySales.cshtml @@ -1,7 +1,7 @@  - + + \ No newline at end of file + + @childAccount.AccountCode + @childAccount.AccountName + @childAccount.TotalBalance + @childAccount.TotalDebitBalance + @childAccount.TotalCreditBalance + + + + + + + + } + + + + + + } + + + *@ + \ No newline at end of file diff --git a/src/AccountGoWeb/Views/Financials/AccountsPrev.cshtml b/src/AccountGoWeb/Views/Financials/AccountsPrev.cshtml new file mode 100644 index 000000000..6837eddf6 --- /dev/null +++ b/src/AccountGoWeb/Views/Financials/AccountsPrev.cshtml @@ -0,0 +1,91 @@ +@model string + +@{ + ViewBag.Title = "Chart of Accounts"; +} +
    +
    +
    +
    +
    + \ No newline at end of file diff --git a/src/AccountGoWeb/Views/Financials/BalanceSheet.cshtml b/src/AccountGoWeb/Views/Financials/BalanceSheet.cshtml index 59ea65cd7..1378569db 100644 --- a/src/AccountGoWeb/Views/Financials/BalanceSheet.cshtml +++ b/src/AccountGoWeb/Views/Financials/BalanceSheet.cshtml @@ -1,18 +1,21 @@ @model ICollection @{ - ViewBag.Title = "BalanceSheet"; - Layout = "~/Views/Shared/_Layout.cshtml"; + ViewBag.Title = "BalanceSheet"; + Layout = "~/Views/Shared/_Layout_bootstrap.cshtml"; } -
    -

    Balance Sheet

    + +@if (Model != null) +{ +
    +

    Balance Sheet

    -
    - - - - - - +
    +
    Account CodeAccount NameAmount
    + + + + + @foreach (var asset in Model.Where(a => a.AccountClassId == 1)) { @@ -21,52 +24,62 @@ } - - - - -
    Account CodeAccount NameAmount
    @asset.Amount
    Total Assets@Model.Where(a => a.AccountClassId == 1).Sum(a => a.Amount)
    + + Total Assets + @Model.Where(a => a.AccountClassId == 1).Sum(a => a.Amount) + +
    -
    - - - - - - - @foreach (var liability in Model.Where(a => a.AccountClassId == 2)) - { - - - - - - } - - - +
    +
    Account CodeAccount NamceAmount
    @Html.ActionLink((string)string.Format("{0}", liability.AccountCode), "account", new { id = liability.AccountId })@liability.AccountName@liability.Amount
    Total Liabilities@Model.Where(a => a.AccountClassId == 2).Sum(a => a.Amount)
    + + + + + + @foreach (var liability in Model.Where(a => a.AccountClassId == 2)) + { + + + + + } + + + +
    Account CodeAccount NamceAmount
    @Html.ActionLink((string)string.Format("{0}", liability.AccountCode), "account", new + { + id = + liability.AccountId + })@liability.AccountName@liability.Amount
    Total Liabilities@Model.Where(a => a.AccountClassId == 2).Sum(a => a.Amount)
    -
    -
    - - - - - - - @foreach (var equity in Model.Where(a => a.AccountClassId == 3)) - { - - - - - - } - - - + +
    +
    Account CodeAccount NamceAmount
    @Html.ActionLink((string)string.Format("{0}", equity.AccountCode), "account", new { id = equity.AccountId })@equity.AccountName@equity.Amount
    Total Equities@Model.Where(a => a.AccountClassId == 3).Sum(a => a.Amount)
    + + + + + + @foreach (var equity in Model.Where(a => a.AccountClassId == 3)) + { + + + + + } + + + +
    Account CodeAccount NamceAmount
    @Html.ActionLink((string)string.Format("{0}", equity.AccountCode), "account", new { id = equity.AccountId }) + @equity.AccountName@equity.Amount
    Total Equities@Model.Where(a => a.AccountClassId == 3).Sum(a => a.Amount)
    -
    +
    +} +else +{ +

    Error fetching data.

    +} \ No newline at end of file diff --git a/src/AccountGoWeb/Views/Financials/Banks.cshtml b/src/AccountGoWeb/Views/Financials/Banks.cshtml index 28e3abb2c..c8075c656 100644 --- a/src/AccountGoWeb/Views/Financials/Banks.cshtml +++ b/src/AccountGoWeb/Views/Financials/Banks.cshtml @@ -1,5 +1,8 @@ @model IEnumerable - +
    diff --git a/src/AccountGoWeb/Views/Financials/IncomeStatement.cshtml b/src/AccountGoWeb/Views/Financials/IncomeStatement.cshtml index dbf6a541e..54cf2ac2e 100644 --- a/src/AccountGoWeb/Views/Financials/IncomeStatement.cshtml +++ b/src/AccountGoWeb/Views/Financials/IncomeStatement.cshtml @@ -1,57 +1,70 @@ @model ICollection + @{ - ViewBag.Title = "IncomeStatement"; - Layout = "~/Views/Shared/_Layout.cshtml"; - var netIncome = Model.Where(a => a.IsExpense == false).Sum(a => a.Amount) - Model.Where(a => a.IsExpense == true).Sum(a => a.Amount); + ViewBag.Title = "Income Statement"; + Layout = "~/Views/Shared/_Layout_bootstrap.cshtml"; + + var netIncome = Model?.Where(a => !a.IsExpense).Sum(a => a.Amount) ?? 0 - + Model?.Where(a => a.IsExpense).Sum(a => a.Amount) ?? 0; }

    Income Statement

    -
    -

    Income Statement

    -
    -
    - - - - - - - @foreach (var asset in Model.Where(a => a.IsExpense == false)) - { +@if (ViewBag.Error != null) +{ +
    @ViewBag.Error
    +} +else if (Model == null || !Model.Any()) +{ +

    No data available to display.

    +} +else +{ +
    +

    Revenues

    +
    Account CodeAccount NameAmount
    - - - + + + - } - - - - -
    @Html.ActionLink((string)string.Format("{0}", asset.AccountCode), "account", new { id = asset.AccountId })@asset.AccountName@asset.AmountAccount CodeAccount NameAmount
    Total Revenues@Model.Where(a => a.IsExpense == false).Sum(a => a.Amount)
    -
    -
    - - - - - - - @foreach (var asset in Model.Where(a => a.IsExpense == true)) - { + @foreach (var item in Model.Where(a => !a.IsExpense)) + { + + + + + + } - - - + + - } - - - - -
    Account CodeAccount NameAmount
    @Html.ActionLink(item.AccountCode, "Account", new { id = item.AccountId })@item.AccountName@item.Amount
    @Html.ActionLink((string)string.Format("{0}", asset.AccountCode), "account", new { id = asset.AccountId })@asset.AccountName@asset.AmountTotal Revenues@Model.Where(a => !a.IsExpense).Sum(a => a.Amount)
    Total Expenses@Model.Where(a => a.IsExpense == true).Sum(a => a.Amount)
    -
    -
    - Net Income: @netIncome -
    \ No newline at end of file + +
    +
    +

    Expenses

    + + + + + + + @foreach (var item in Model.Where(a => a.IsExpense)) + { + + + + + + } + + + + +
    Account CodeAccount NameAmount
    @Html.ActionLink(item.AccountCode, "Account", new { id = item.AccountId })@item.AccountName@item.Amount
    Total Expenses@Model.Where(a => a.IsExpense).Sum(a => a.Amount)
    +
    +
    + Net Income: @netIncome +
    +} diff --git a/src/AccountGoWeb/Views/Financials/TrialBalance.cshtml b/src/AccountGoWeb/Views/Financials/TrialBalance.cshtml index 4bd9d2f1c..ad258f287 100644 --- a/src/AccountGoWeb/Views/Financials/TrialBalance.cshtml +++ b/src/AccountGoWeb/Views/Financials/TrialBalance.cshtml @@ -1,7 +1,7 @@ @model ICollection @{ ViewBag.Title = "TrialBalance"; - Layout = "~/Views/Shared/_Layout.cshtml"; + Layout = "~/Views/Shared/_Layout_bootstrap.cshtml"; }

    diff --git a/src/AccountGoWeb/Views/Home/Index.cshtml b/src/AccountGoWeb/Views/Home/Index.cshtml index c1bfb55ba..a0a4470f7 100644 --- a/src/AccountGoWeb/Views/Home/Index.cshtml +++ b/src/AccountGoWeb/Views/Home/Index.cshtml @@ -1,10 +1,23 @@ -
    -
    - @Html.Partial("~/Views/Dashboard/_MonthlySales.cshtml") +@inject IConfiguration _configuration +
    +
    + +
    +
    +

    @_configuration["GoodDeeds:SuperOrganizationName"]

    -
    +
    + +
    -
    +
    +
    +
    + @* *@ + @* *@ +
    +
    +
    diff --git a/src/AccountGoWeb/Views/Inventory/Items.cshtml b/src/AccountGoWeb/Views/Inventory/Index.cshtml similarity index 90% rename from src/AccountGoWeb/Views/Inventory/Items.cshtml rename to src/AccountGoWeb/Views/Inventory/Index.cshtml index c336efead..c9e73bd99 100644 --- a/src/AccountGoWeb/Views/Inventory/Items.cshtml +++ b/src/AccountGoWeb/Views/Inventory/Index.cshtml @@ -1,7 +1,7 @@ @model string
    - + New Item @@ -16,7 +16,7 @@ \ No newline at end of file + + +
    +
    + @Html.ValidationSummary(true) +
    +
    +
    +
    Vendor Name
    +
    + + +
    +
    + @* Invoice Date *@ +
    +
    Date
    +
    + +
    +
    + @* Amount Paid *@ +
    +
    Amount Paid
    +
    + +
    +
    + @* Is Paid *@ +
    +
    Is Paid
    +
    + +
    +
    +
    + + + + + + + + + + + @for (int i = 0; i < Model.PurchaseInvoiceLines.Count; i++) + { + + + + + + + + } + + + + +
    ItemQuantityAmountDiscountMeasurement
    + @Html.DropDownListFor(model => model.PurchaseInvoiceLines[i].ItemId, + (IEnumerable)ViewBag.Items, new + { + @class = "form-control", + id = + "optItem" + }) + + + @Html.EditorFor(model => model.PurchaseInvoiceLines[i].Quantity, new + { + htmlAttributes = new + { + @class = "form-control" + } + }) + + @Html.EditorFor(model => model.PurchaseInvoiceLines[i].Amount, new + { + htmlAttributes = new + { + @class = "form-control" + } + }) + + @Html.EditorFor(model => model.PurchaseInvoiceLines[i].Discount, new + { + htmlAttributes = new + { + @class = "form-control" + } + }) + + @Html.DropDownListFor(model => model.PurchaseInvoiceLines[i].MeasurementId, + (IEnumerable)ViewBag.Measurements, + new { @class = "form-control", id = $"optMeasurement_{i}" }) + +
    + +
    +
    +
    + +
    + + Close +
    +
    \ No newline at end of file diff --git a/src/AccountGoWeb/Views/Purchasing/AddPurchaseOrder.cshtml b/src/AccountGoWeb/Views/Purchasing/AddPurchaseOrder.cshtml index 4b086b498..698a7982c 100644 --- a/src/AccountGoWeb/Views/Purchasing/AddPurchaseOrder.cshtml +++ b/src/AccountGoWeb/Views/Purchasing/AddPurchaseOrder.cshtml @@ -1,2 +1,111 @@ -
    - +@model Dto.Purchasing.PurchaseOrder + + + +
    +
    + @Html.ValidationSummary(true) +
    +
    +
    +
    Vendor Name
    +
    + + +
    +
    +
    +
    Completed
    +
    + +
    +
    +
    +
    Date
    +
    + + +
    +
    +
    + + + + + + + + + + @for (int i = 0; i < Model.PurchaseOrderLines.Count; i++) { + + + + + + + + } + + + + + +
    ItemQuantityAmountDiscountMeasurement
    + @Html.DropDownListFor(model => model.PurchaseOrderLines[i].ItemId, + (IEnumerable)ViewBag.Items, + new { + @class = "form-control", + id = + "optItem" + }) + + + @Html.EditorFor(model => model.PurchaseOrderLines[i].Quantity, + new { + htmlAttributes = new { + @class = "form-control" + } + }) + + @Html.EditorFor(model => model.PurchaseOrderLines[i].Amount, + new { + htmlAttributes = new { + @class = "form-control" + } + }) + + @Html.EditorFor(model => model.PurchaseOrderLines[i].Discount, + new { + htmlAttributes = new { + @class = "form-control" + } + }) + + @Html.DropDownListFor(model => model.PurchaseOrderLines[i].MeasurementId, + (IEnumerable)ViewBag.Measurements, + new { @class = "form-control", id = $"optMeasurement_{i}" }) + +
    + +
    +
    + +
    + + Close +
    +
    +
    +@*
    *@ +@* *@ \ No newline at end of file diff --git a/src/AccountGoWeb/Views/Purchasing/PurchaseInvoice.cshtml b/src/AccountGoWeb/Views/Purchasing/PurchaseInvoice.cshtml index b15e3d4f7..50b7522a0 100644 --- a/src/AccountGoWeb/Views/Purchasing/PurchaseInvoice.cshtml +++ b/src/AccountGoWeb/Views/Purchasing/PurchaseInvoice.cshtml @@ -1,3 +1,139 @@ -
    +@model Dto.Purchasing.PurchaseInvoice - \ No newline at end of file + + + + +
    +
    + @Html.HiddenFor(m => m.Id) +
    +
    +
    +
    +
    Vendor Name
    +
    + + + @Html.HiddenFor(m => m.VendorId) +
    +
    + @* Amount *@ +
    +
    Amount
    +
    + @Model.Amount +
    +
    + @* Amount Paid *@ +
    +
    Amount Paid
    +
    + @Model.AmountPaid +
    +
    + @* Invoice Date *@ +
    +
    Invoice Date
    +
    + @Model.InvoiceDate +
    +
    + @* Posted *@ +
    +
    Posted
    +
    + @Model.Posted +
    +
    + @* Is Paid *@ +
    +
    Is Paid
    +
    + @Model.IsPaid +
    +
    +
    + + @* Table *@ + + + + + + + + + + @for (int i = 0; i < Model.PurchaseInvoiceLines.Count; i++) + { + + + + + + + + } + +
    ItemQuantityAmountDiscountMeasurement
    + + + + + + + + + + + + + + +
    +
    +
    +
    + +
    + + Close +
    +
    + +@section scripts{ + + +} \ No newline at end of file diff --git a/src/AccountGoWeb/Views/Purchasing/PurchaseInvoices.cshtml b/src/AccountGoWeb/Views/Purchasing/PurchaseInvoices.cshtml index 83e2d27c4..db94d0df4 100644 --- a/src/AccountGoWeb/Views/Purchasing/PurchaseInvoices.cshtml +++ b/src/AccountGoWeb/Views/Purchasing/PurchaseInvoices.cshtml @@ -45,7 +45,7 @@ selectedRow = selectedRows[0]; document.getElementById('linkMakePayment').setAttribute('href', 'payment/' + selectedRow.id); - document.getElementById('linkViewInvoice').setAttribute('href', 'purchaseinvoice?invoiceId=' + selectedRow.id); + document.getElementById('linkViewInvoice').setAttribute('href', 'purchaseinvoice?id=' + selectedRow.id); if(!selectedRow.isPaid && selectedRow.posted) document.getElementById('linkMakePayment').setAttribute('class', 'btn'); diff --git a/src/AccountGoWeb/Views/Purchasing/PurchaseOrder.cshtml b/src/AccountGoWeb/Views/Purchasing/PurchaseOrder.cshtml index a7f10ffe4..79c33fc6f 100644 --- a/src/AccountGoWeb/Views/Purchasing/PurchaseOrder.cshtml +++ b/src/AccountGoWeb/Views/Purchasing/PurchaseOrder.cshtml @@ -1,2 +1,127 @@ -
    - \ No newline at end of file +@model Dto.Purchasing.PurchaseOrder + + + + + +
    +
    + @Html.HiddenFor(m => m.Id) +
    +
    +
    +
    +
    Vendor Name
    +
    + + + @Html.HiddenFor(m => m.VendorId) +
    +
    + @* Amount *@ +
    +
    Amount
    +
    + @Model.Amount +
    +
    + @* Order Date *@ +
    +
    Order Date
    +
    + + +
    +
    + @* Completed *@ +
    +
    Completed
    +
    + + +
    +
    +
    + + @* Table *@ + + + + + + + + + + @for (int i = 0; i < Model.PurchaseOrderLines.Count; i++) + { + + + + + + + + } + +
    ItemQuantityAmountDiscountMeasurement
    + + + + + + + + + + + + + + +
    +
    +
    +
    + +
    + + Close +
    +
    + +@section scripts{ + + +} \ No newline at end of file diff --git a/src/AccountGoWeb/Views/Purchasing/PurchaseOrders.cshtml b/src/AccountGoWeb/Views/Purchasing/PurchaseOrders.cshtml index 397531fd4..21a03aa84 100644 --- a/src/AccountGoWeb/Views/Purchasing/PurchaseOrders.cshtml +++ b/src/AccountGoWeb/Views/Purchasing/PurchaseOrders.cshtml @@ -42,7 +42,7 @@ //document.getElementById('linkNewReceipt').setAttribute('href', 'addreceipt?purchId=' + selectedRow.id); document.getElementById('linkCreateInvoice').setAttribute('href', 'addpurchaseinvoice?purchId=' + selectedRow.id); - document.getElementById('linkViewOrder').setAttribute('href', 'purchaseorder?purchId=' + selectedRow.id); + document.getElementById('linkViewOrder').setAttribute('href', 'purchaseorder?id=' + selectedRow.id); if(selectedRow.purchaseInvoiceHeaderId === undefined){ document.getElementById('linkCreateInvoice').setAttribute('class', 'btn'); @@ -60,16 +60,16 @@ } - //if(selectedRow.completed) - //{ - // document.getElementById('linkCreateInvoice').setAttribute('class', ''); - // document.getElementById('linkNewReceipt').setAttribute('class', 'inactiveLink'); - //} - //else - //{ - // document.getElementById('linkCreateInvoice').setAttribute('class', 'inactiveLink'); - // document.getElementById('linkNewReceipt').setAttribute('class', ''); - //} + if(selectedRow.completed) + { + document.getElementById('linkCreateInvoice').setAttribute('class', ''); + document.getElementById('linkNewReceipt').setAttribute('class', 'inactiveLink'); + } + else + { + document.getElementById('linkCreateInvoice').setAttribute('class', 'inactiveLink'); + document.getElementById('linkNewReceipt').setAttribute('class', ''); + } } // wait for the document to be loaded, otherwise diff --git a/src/AccountGoWeb/Views/Purchasing/Vendor.cshtml b/src/AccountGoWeb/Views/Purchasing/Vendor.cshtml index 188989895..27e3a21d8 100644 --- a/src/AccountGoWeb/Views/Purchasing/Vendor.cshtml +++ b/src/AccountGoWeb/Views/Purchasing/Vendor.cshtml @@ -1,5 +1,11 @@ @model Dto.Purchasing.Vendor + + diff --git a/src/AccountGoWeb/Views/Quotations/AddSalesQuotation.cshtml b/src/AccountGoWeb/Views/Quotations/AddSalesQuotation.cshtml index 14d4e4d7e..eddd20580 100644 --- a/src/AccountGoWeb/Views/Quotations/AddSalesQuotation.cshtml +++ b/src/AccountGoWeb/Views/Quotations/AddSalesQuotation.cshtml @@ -1,2 +1,131 @@ -
    - +@model Dto.Sales.SalesQuotation + + + + +
    +
    + @Html.ValidationSummary(true) +
    +
    + @* Customer *@ +
    +
    Customer
    +
    + + +
    +
    + @* Payment Term *@ +
    +
    Payment Term
    +
    + + +
    +
    +
    + + + + + + + + + + @for (int i = 0; i < Model.SalesQuotationLines.Count; i++) + { + + + + + + + + + } + + + + +
    ItemQuantityAmountDiscountMeasurement
    + @Html.DropDownListFor(model => model.SalesQuotationLines[i].ItemId, + (IEnumerable)ViewBag.Items, new { @class = "form-control", id = "optItem" }) + + + @Html.EditorFor(model => model.SalesQuotationLines[i].Quantity, new + { + htmlAttributes = new + { + @class = "form-control" + } + }) + + @Html.EditorFor(model => model.SalesQuotationLines[i].Amount, new + { + htmlAttributes = new + { + @class = "form-control" + } + }) + + @Html.EditorFor(model => model.SalesQuotationLines[i].Discount, new + { + htmlAttributes = new + { + @class = "form-control" + } + }) + + @Html.DropDownListFor(model => model.SalesQuotationLines[i].MeasurementId, + (IEnumerable)ViewBag.Measurements, + new { @class = "form-control", id = $"optMeasurement_{i}" }) + +
    + +
    +
    +
    +
    +
    + +@section scripts { + +} \ No newline at end of file diff --git a/src/AccountGoWeb/Views/Quotations/Quotation.cshtml b/src/AccountGoWeb/Views/Quotations/Quotation.cshtml index 11cae02cc..8035de6ef 100644 --- a/src/AccountGoWeb/Views/Quotations/Quotation.cshtml +++ b/src/AccountGoWeb/Views/Quotations/Quotation.cshtml @@ -1,2 +1,122 @@ -
    - \ No newline at end of file +@model Dto.Sales.SalesQuotation + + + + + +
    +
    + @Html.HiddenFor(m => m.Id) +
    +
    +
    + @* Customer Name *@ +
    +
    Customer Name
    +
    + + + @Html.HiddenFor(m => m.CustomerId) +
    +
    + @* Quotation Date *@ +
    +
    Quotation Date
    +
    + +
    +
    + @* Payment Term *@ +
    +
    Payment Term
    +
    @ViewBag.PaymentTermId
    +
    + @* Total Amount *@ +
    +
    Total Amount
    +
    @ViewBag.TotalAmount
    +
    +
    + @* Table *@ + + + + + + + + + + @for (int i = 0; i < Model.SalesQuotationLines.Count; i++) { + + + + + + + + } + +
    ItemQuantityAmountDiscountMeasurement
    + + + + + + + + + + + + + + +
    +
    +
    +
    +
    + + Close +
    +
    + +@section scripts{ + + +} \ No newline at end of file diff --git a/src/AccountGoWeb/Views/Quotations/Quotations.cshtml b/src/AccountGoWeb/Views/Quotations/Quotations.cshtml index 052bcac1d..bfe7f309f 100644 --- a/src/AccountGoWeb/Views/Quotations/Quotations.cshtml +++ b/src/AccountGoWeb/Views/Quotations/Quotations.cshtml @@ -15,7 +15,7 @@
    -
    +
    @@ -43,11 +43,9 @@ var selectedRows = gridOptions.api.getSelectedRows(); selectedRow = selectedRows[0]; - document.getElementById('linkViewQuotation').setAttribute('href', 'quotation?id=' + selectedRow.id); + document.getElementById('linkViewQuotation').setAttribute('href', 'Quotation?id=' + selectedRow.id); document.getElementById('linkViewQuotation').setAttribute('class', 'btn'); - - if(selectedRow.status == 3) { document.getElementById('linkNewOrder').setAttribute('class', 'btn inactiveLink'); @@ -56,9 +54,6 @@ document.getElementById('linkNewOrder').setAttribute('href', '/sales/salesorder?quotationId=' + selectedRow.id); document.getElementById('linkNewOrder').setAttribute('class', 'btn'); } - - - } // wait for the document to be loaded, otherwise diff --git a/src/AccountGoWeb/Views/Sales/AddReceipt.cshtml b/src/AccountGoWeb/Views/Sales/AddReceipt.cshtml index 36996ae05..0f9ede2f1 100644 --- a/src/AccountGoWeb/Views/Sales/AddReceipt.cshtml +++ b/src/AccountGoWeb/Views/Sales/AddReceipt.cshtml @@ -1,6 +1,12 @@ @model AccountGoWeb.Models.Sales.AddReceipt -
    + + +
    @Html.ValidationSummary(true)
    diff --git a/src/AccountGoWeb/Views/Sales/AddSalesInvoice.cshtml b/src/AccountGoWeb/Views/Sales/AddSalesInvoice.cshtml index 356e804ee..17bd3f528 100644 --- a/src/AccountGoWeb/Views/Sales/AddSalesInvoice.cshtml +++ b/src/AccountGoWeb/Views/Sales/AddSalesInvoice.cshtml @@ -1,3 +1,154 @@ -
    +@model Dto.Sales.SalesInvoice - \ No newline at end of file + + + +
    + @Html.AntiForgeryToken() + @Html.ValidationSummary(true) +
    +
    + @* Customer *@ +
    +
    Customer
    +
    + + +
    +
    + @* Payment Term *@ +
    +
    Payment Term
    +
    + + +
    +
    + @* Posted *@ +
    +
    Posted
    +
    + + + +
    +
    + + + + + + + + + + + @for (int i = 0; i < Model.SalesInvoiceLines!.Count; i++) + { + + + + + + + + } + +
    ItemQuantityAmountDiscountMeasurement
    + + + + + + + + + + + + + + +
    +
    +
    +
    +
    + + Close +
    + + + diff --git a/src/AccountGoWeb/Views/Sales/AddSalesOrder.cshtml b/src/AccountGoWeb/Views/Sales/AddSalesOrder.cshtml index 9672f8008..dcfbc4315 100644 --- a/src/AccountGoWeb/Views/Sales/AddSalesOrder.cshtml +++ b/src/AccountGoWeb/Views/Sales/AddSalesOrder.cshtml @@ -1,3 +1,117 @@ -
    +@model Dto.Sales.SalesOrder + +
    +
    + @Html.AntiForgeryToken() + @Html.ValidationSummary(true) +
    +
    +
    +
    Customer
    +
    + + +
    +
    + @* Payment Term *@ +
    +
    Payment Term
    +
    + + +
    +
    + @* Amount *@ +
    +
    Amount
    +
    + + +
    +
    + +
    + + + + + + + + + @for (int i = 0; i < Model.SalesOrderLines.Count; i++) + { + + + + + + + + } + +
    ItemQuantityAmountDiscountMeasurement
    + @Html.DropDownListFor(model => model.SalesOrderLines[i].ItemId, + (IEnumerable)ViewBag.Items, new { @class = "form-control", id = "optItem" }) + + + @Html.EditorFor(model => model.SalesOrderLines[i].Quantity, new + { + htmlAttributes = new + { + @class = "form-control" + } + }) + + @Html.EditorFor(model => model.SalesOrderLines[i].Amount, new + { + htmlAttributes = new + { + @class = "form-control" + } + }) + + @Html.EditorFor(model => model.SalesOrderLines[i].Discount, new + { + htmlAttributes = new + { + @class = "form-control" + } + }) + + @Html.DropDownListFor(model => model.SalesOrderLines[i].MeasurementId, + (IEnumerable)ViewBag.Measurements, + new { @class = "form-control", id = $"optMeasurement_{i}" }) + +
    + +
    +
    +
    + + Close +
    +
    +@section Scripts { + +} \ No newline at end of file diff --git a/src/AccountGoWeb/Views/Sales/Allocate.cshtml b/src/AccountGoWeb/Views/Sales/Allocate.cshtml index 20c1631d3..fbabf6627 100644 --- a/src/AccountGoWeb/Views/Sales/Allocate.cshtml +++ b/src/AccountGoWeb/Views/Sales/Allocate.cshtml @@ -1,12 +1,14 @@ @model AccountGoWeb.Models.Sales.Allocate -
    + + @Html.AntiForgeryToken()

    General

    -
    @@ -55,7 +57,8 @@

    Invoice

    -
    @@ -86,7 +89,8 @@ @Model.AllocationLines[i].AllocatedAmount - + } @@ -100,4 +104,29 @@ Close
    - \ No newline at end of file + + + \ No newline at end of file diff --git a/src/AccountGoWeb/Views/Sales/Customer.cshtml b/src/AccountGoWeb/Views/Sales/Customer.cshtml index c5bc35a1d..e109b975a 100644 --- a/src/AccountGoWeb/Views/Sales/Customer.cshtml +++ b/src/AccountGoWeb/Views/Sales/Customer.cshtml @@ -1,4 +1,10 @@ @model Dto.Sales.Customer + +
    -
    + @*
    Fax
    -
    +
    *@
    Website
    @@ -73,13 +79,13 @@
    First Name
    - +
    Last Name
    - +
    @@ -87,25 +93,25 @@
    Phone
    - +
    -
    + @*
    Fax
    -
    +
    *@
    Website
    - +
    Email
    - +
    diff --git a/src/AccountGoWeb/Views/Sales/DonationInvoice.cshtml b/src/AccountGoWeb/Views/Sales/DonationInvoice.cshtml new file mode 100644 index 000000000..089d40d95 --- /dev/null +++ b/src/AccountGoWeb/Views/Sales/DonationInvoice.cshtml @@ -0,0 +1,121 @@ +@model Dto.Sales.SalesInvoice + + + +
    + +
    +
    + @Html.HiddenFor(m => m.Id) +
    +
    +
    + @* ID *@ +
    +
    ID
    +
    @Model.Id
    +
    + @* Customer Name *@ +
    +
    Customer Name
    +
    + + + @Html.HiddenFor(m => m.CustomerId) +
    +
    + @* Invoice Date *@ +
    +
    Invoice Date
    +
    + +
    +
    + @* Total Amount *@ +
    +
    Total Amount
    +
    @ViewBag.TotalAmount
    +
    +
    +
    + + @* Table *@ + + + + + + + + + + @for (int i = 0; i < Model.SalesInvoiceLines!.Count; i++) + { + + + + + + + + } + +
    ItemQuantityAmountDiscountMeasurement
    + + + + + + + + + + + + + + +
    +
    +
    +
    + + Close +
    +
    + +@section scripts{ + + +} \ No newline at end of file diff --git a/src/AccountGoWeb/Views/Sales/DonationInvoices.cshtml b/src/AccountGoWeb/Views/Sales/DonationInvoices.cshtml new file mode 100644 index 000000000..d1d7592cc --- /dev/null +++ b/src/AccountGoWeb/Views/Sales/DonationInvoices.cshtml @@ -0,0 +1,54 @@ +@model string + + +
    +
    +
    + \ No newline at end of file diff --git a/src/AccountGoWeb/Views/Sales/SalesInvoice.cshtml b/src/AccountGoWeb/Views/Sales/SalesInvoice.cshtml index 797c1b185..e5abbb8b5 100644 --- a/src/AccountGoWeb/Views/Sales/SalesInvoice.cshtml +++ b/src/AccountGoWeb/Views/Sales/SalesInvoice.cshtml @@ -1,2 +1,122 @@ -
    - \ No newline at end of file +@model Dto.Sales.SalesInvoice +@using System.Globalization + + +
    +
    + @Html.HiddenFor(m => m.Id) +
    +
    +
    + @* ID *@ +
    + + +
    ID
    +
    @Model.Id
    +
    + @* Customer Name *@ +
    +
    Customer Name
    +
    + + + @Html.HiddenFor(m => m.CustomerId) +
    +
    + @* Invoice Date *@ +
    +
    Invoice Date
    +
    + +
    +
    + @* Total Amount *@ +
    +
    Total Amount
    +
    @String.Format("{0:F2}", ViewBag.TotalAmount)
    +
    +
    +
    + + @* Table *@ + + + + + + + + + + @for (int i = 0; i < Model.SalesInvoiceLines!.Count; i++) + { + + + + + + + + } + +
    ItemQuantityAmountDiscountMeasurement
    + + + + + + + + + + + + + + + +
    +
    +
    +
    + + Close +
    +
    + +@section scripts{ + + +} \ No newline at end of file diff --git a/src/AccountGoWeb/Views/Sales/SalesInvoicePdf.cshtml b/src/AccountGoWeb/Views/Sales/SalesInvoicePdf.cshtml index 66b64f01e..6ce978657 100644 --- a/src/AccountGoWeb/Views/Sales/SalesInvoicePdf.cshtml +++ b/src/AccountGoWeb/Views/Sales/SalesInvoicePdf.cshtml @@ -114,7 +114,7 @@ apply the skin class to the body tag so the changes take effect. - @foreach (var item in Model.SalesInvoiceLines) + @foreach (var item in Model.SalesInvoiceLines!) { diff --git a/src/AccountGoWeb/Views/Sales/SalesInvoices.cshtml b/src/AccountGoWeb/Views/Sales/SalesInvoices.cshtml index 247e1c76f..b811ab6e0 100644 --- a/src/AccountGoWeb/Views/Sales/SalesInvoices.cshtml +++ b/src/AccountGoWeb/Views/Sales/SalesInvoices.cshtml @@ -1,53 +1,104 @@ @model string + +
    - \ No newline at end of file +@* Delete Modal*@ + + +@section scripts{ + +} diff --git a/src/AccountGoWeb/Views/Sales/SalesOrder.cshtml b/src/AccountGoWeb/Views/Sales/SalesOrder.cshtml index 1a31098f3..d3cbc83b6 100644 --- a/src/AccountGoWeb/Views/Sales/SalesOrder.cshtml +++ b/src/AccountGoWeb/Views/Sales/SalesOrder.cshtml @@ -1,2 +1,63 @@ -
    - \ No newline at end of file +@model Dto.Sales.SalesOrder + + + + +
    +
    +
    +
    +
    +
    +
    Customer Name
    +
    @ViewBag.CustomerName
    +
    + @* Order Date *@ +
    +
    Order Date
    +
    @ViewBag.OrderDate
    +
    + @* Total Amount *@ +
    +
    Total Amount
    +
    @ViewBag.TotalAmount
    +
    + + + + + + + + + + @for (int i = 0; i < Model.SalesOrderLines.Count; i++) + { + + + + + + + + } + +
    ItemQuantityAmountDiscountMeasurement
    @Model.SalesOrderLines[i].ItemDescription@Model.SalesOrderLines[i].Quantity@Model.SalesOrderLines[i].Amount@Model.SalesOrderLines[i].Discount@Model.SalesOrderLines[i].MeasurementDescription
    +
    +
    +
    +
    +
    \ No newline at end of file diff --git a/src/AccountGoWeb/Views/Sales/SalesReceipt.cshtml b/src/AccountGoWeb/Views/Sales/SalesReceipt.cshtml new file mode 100644 index 000000000..7aaef6632 --- /dev/null +++ b/src/AccountGoWeb/Views/Sales/SalesReceipt.cshtml @@ -0,0 +1,27 @@ +@model Dto.Sales.SalesReceipt + + + +
    +
    + @Html.HiddenFor(m => m.Id) +
    +
    +
    +
    +
    ID
    +
    @Model.Id
    +
    +
    +
    +
    +
    +
    \ No newline at end of file diff --git a/src/AccountGoWeb/Views/Sales/SalesReceipts.cshtml b/src/AccountGoWeb/Views/Sales/SalesReceipts.cshtml index 9aa7ccb2a..1e7c26f66 100644 --- a/src/AccountGoWeb/Views/Sales/SalesReceipts.cshtml +++ b/src/AccountGoWeb/Views/Sales/SalesReceipts.cshtml @@ -1,14 +1,26 @@ @model string + +
    @@ -18,39 +30,69 @@ var selectedRow = {}; var columnDefs = [ - {headerName: "Receipt", field: "id", width: 50}, - {headerName: "No", field: "receiptNo", width: 50}, - {headerName: "Customer Name", field: "customerName", width: 350}, - {headerName: "Receipt Date", field: "receiptDate", width: 100}, - {headerName: "Amount", field: "amount", width: 100}, - {headerName: "Left to Allocate", field: "remainingAmountToAllocate", width: 100} + { headerName: "Receipt", field: "id", width: 50 }, + { headerName: "No", field: "receiptNo", width: 50 }, + { headerName: "Customer Name", field: "customerName", width: 350 }, + { headerName: "Receipt Date", field: "receiptDate", width: 100 }, + { headerName: "Amount", field: "amount", width: 100 }, + { headerName: "Left to Allocate", field: "remainingAmountToAllocate", width: 100 } ]; var gridOptions = { columnDefs: columnDefs, rowData: @Html.Raw(Model), enableSorting: true, - // PROPERTIES - simple boolean / string / number properties rowSelection: 'single', onSelectionChanged: onSelectionChanged, + rowClassRules: { + 'highlighted-row': params => params.node.isSelected() // Add 'highlighted-row' to selected rows + }, }; function onSelectionChanged() { + console.log("Selection changed"); + + // Get all selected rows var selectedRows = gridOptions.api.getSelectedRows(); + console.log("Selected rows:", selectedRows); + + if (!selectedRows.length) { + console.log("No row selected"); + return; // Exit if no row is selected + } + + // Get the selected row selectedRow = selectedRows[0]; + console.log("Selected row data:", selectedRow); + + // Update the Allocate and View Receipt links + document.getElementById('linkAllocate').setAttribute('href', '/sales/allocate/' + selectedRow.id); + console.log("Updated Allocate link to:", 'allocate/' + selectedRow.id); - document.getElementById('linkAllocate').setAttribute('href', 'allocate/' + selectedRow.id); + document.getElementById('linkViewReceipt').setAttribute('href', '/sales/SalesReceipt?id=' + selectedRow.id); + console.log("Updated View Receipt link to:", 'SalesReceipt?id=' + selectedRow.id); - if(selectedRow.remainingAmountToAllocate > 0) + document.getElementById('linkViewReceipt').setAttribute('class', 'btn'); + + if (selectedRow.remainingAmountToAllocate > 0) { document.getElementById('linkAllocate').setAttribute('class', 'btn'); - else + console.log("Set Allocate button to active"); + } else { document.getElementById('linkAllocate').setAttribute('class', 'btn inactiveLink'); + console.log("Set Allocate button to inactive"); + } + + // Highlight the selected row + gridOptions.api.forEachNode(node => { + console.log("Processing row node with ID:", node.data.id); + node.setSelected(node.data.id === selectedRow.id); // Mark row as selected + }); } - // wait for the document to be loaded, otherwise - // ag-Grid will not find the div in the document. - document.addEventListener("DOMContentLoaded", function() { + document.addEventListener("DOMContentLoaded", function () { + console.log("Document loaded"); var eGridDiv = document.querySelector('#receipts'); new agGrid.Grid(eGridDiv, gridOptions); + console.log("ag-Grid initialized"); }); - \ No newline at end of file + diff --git a/src/AccountGoWeb/Views/Sales/salesorders.cshtml b/src/AccountGoWeb/Views/Sales/salesorders.cshtml index 81d7d9616..de9802629 100644 --- a/src/AccountGoWeb/Views/Sales/salesorders.cshtml +++ b/src/AccountGoWeb/Views/Sales/salesorders.cshtml @@ -43,8 +43,9 @@ function onSelectionChanged() { var selectedRows = gridOptions.api.getSelectedRows(); selectedRow = selectedRows[0]; + console.log(selectedRows); - document.getElementById('linkViewOrder').setAttribute('href', 'salesorder?orderId=' + selectedRow.id); + document.getElementById('linkViewOrder').setAttribute('href', 'SalesOrder?id=' + selectedRow.id); document.getElementById('linkViewOrder').setAttribute('class', 'btn'); document.getElementById('linkNewInvoice').setAttribute('href', 'salesinvoice?orderId=' + selectedRow.id); diff --git a/src/AccountGoWeb/Views/Shared/_Layout.cshtml b/src/AccountGoWeb/Views/Shared/_Layout.cshtml index 5e8ea9be4..33598b1b1 100644 --- a/src/AccountGoWeb/Views/Shared/_Layout.cshtml +++ b/src/AccountGoWeb/Views/Shared/_Layout.cshtml @@ -1,133 +1,44 @@ -@{ Layout = ""; } - + + + AccountGo + - - - - - + + + - + + +
    - - - - - + @* *@ +
    - +

    @RenderBody()
    @@ -643,14 +560,18 @@
    - - - - - - - + + + + + + + + + + @* *@ + @RenderSection("Scripts", required: false) diff --git a/src/AccountGoWeb/Views/Shared/_LayoutPrev.cshtml b/src/AccountGoWeb/Views/Shared/_LayoutPrev.cshtml index ce08a0f74..6cdebb9af 100644 --- a/src/AccountGoWeb/Views/Shared/_LayoutPrev.cshtml +++ b/src/AccountGoWeb/Views/Shared/_LayoutPrev.cshtml @@ -57,9 +57,9 @@
    + +@* Delete Modal*@ + + + + + + @section scripts{ - - + + + + + + + + + + + + diff --git a/src/BlazorGDB/BlazorGDB/Components/Layout/MainLayout.razor b/src/BlazorGDB/BlazorGDB/Components/Layout/MainLayout.razor new file mode 100644 index 000000000..64048e7ac --- /dev/null +++ b/src/BlazorGDB/BlazorGDB/Components/Layout/MainLayout.razor @@ -0,0 +1,115 @@ +@inherits LayoutComponentBase + +@*
    + + +
    +
    + About +
    + +
    + @Body +
    +
    +
    + +
    + An unhandled error has occurred. + Reload + 🗙 +
    *@ + +
    + + + +
    +
    + About +
    + +
    +
    @Body
    +
    +
    + +
    + +@code { + Sidebar? sidebar; + IEnumerable? navItems; + + private async Task SidebarDataProvider(SidebarDataProviderRequest request) + { + if (navItems is null) + navItems = GetNavItems(); + + return await Task.FromResult(request.ApplyTo(navItems)); + } + + // https://icons.getbootstrap.com/ + + private IEnumerable GetNavItems() + { + navItems = new List + { + new NavItem { Id = "10", Href = "/", IconName = IconName.HouseDoorFill, Text = "Dashboard", Match=NavLinkMatch.All}, + + new NavItem { Id = "20", IconName = IconName.Activity, Text = "Accounts Receivable" }, + new NavItem { Id = "21", Href = "/receivables/sales-quotations", CustomIconName = "bi bi-currency-dollar", Text = "Sales Quotations", ParentId="20"}, + new NavItem { Id = "22", Href = "/receivables/sales-orders", IconName = IconName.Alarm, Text = "Sales Orders", ParentId="20"}, + new NavItem { Id = "23", Href = "/receivables/sales-receipts", IconName = IconName.CheckAll, Text = "Sales Receipts", ParentId="20"}, + new NavItem { Id = "24", Href = "/receivables/sales-invoices", IconName = IconName.CheckAll, Text = "Sales Invoices", ParentId="20"}, + new NavItem { Id = "25", Href = "/receivables/donation-invoices", IconName = IconName.CheckAll, Text = "Donation Invoices", ParentId="20"}, + new NavItem { Id = "26", Href = "/receivables/customers", IconName = IconName.CheckAll, Text = "Customers", ParentId="20"}, + + new NavItem { Id = "30", IconName = IconName.WindowPlus, Text = "Accounts Payable" }, + new NavItem { Id = "31", Href = "/payables/purchase-orders", CustomIconName = "bi bi-pencil", Text = "Purchase Orders", ParentId="30"}, + new NavItem { Id = "32", Href = "/payables/purchase-invoices", CustomIconName = "bi bi-laptop-fill", Text = "Purchase Invoices", ParentId="30"}, + new NavItem { Id = "33", Href = "/payables/vendors", CustomIconName = "bi bi-globe2", Text = "Vendors", ParentId="30"}, + + new NavItem { Id = "40", IconName = IconName.WindowPlus, Text = "Inventory" }, + new NavItem { Id = "41", Href = "/inventory/inventory-control-journal", CustomIconName = "bi bi-pencil", Text = "Inventory Control Journal", ParentId="40"}, + new NavItem { Id = "42", Href = "/inventory/items", CustomIconName = "bi bi-laptop-fill", Text = "Items", ParentId="40"}, + + new NavItem { Id = "50", IconName = IconName.WindowPlus, Text = "Financials" }, + new NavItem { Id = "51", Href = "/financials/journal-entries", CustomIconName = "bi bi-currency-dollar", Text = "Journal Entries", ParentId="50"}, + new NavItem { Id = "52", Href = "/financials/general-ledgers", IconName = IconName.Alarm, Text = "General Ledgers", ParentId="50"}, + new NavItem { Id = "53", Href = "/financials/taxes", IconName = IconName.CheckAll, Text = "Taxes", ParentId="50"}, + new NavItem { Id = "54", Href = "/financials/chart-of-accounts", IconName = IconName.CheckAll, Text = "Chart of Accounts", ParentId="50"}, + new NavItem { Id = "55", Href = "/b/financials/chart-of-accounts", IconName = IconName.CheckAll, Text = "Chart of Accounts (wasm)", ParentId="50"}, + new NavItem { Id = "56", Href = "/financials/banks", IconName = IconName.CheckAll, Text = "Banks", ParentId="50"}, + + new NavItem { Id = "60", IconName = IconName.WindowPlus, Text = "Reports" }, + new NavItem { Id = "61", Href = "/reports/balance-sheet", CustomIconName = "bi bi-pencil", Text = "Balance Sheet", ParentId="60"}, + new NavItem { Id = "62", Href = "/reports/income-statement", CustomIconName = "bi bi-laptop-fill", Text = "Income Statement", ParentId="60"}, + new NavItem { Id = "63", Href = "/reports/trial-balance", CustomIconName = "bi bi-globe2", Text = "Trial Balance", ParentId="60"}, + + new NavItem { Id = "70", IconName = IconName.WindowPlus, Text = "Organization" }, + new NavItem { Id = "71", Href = "/organization/company", CustomIconName = "bi bi-pencil", Text = "Company", ParentId="70"}, + new NavItem { Id = "72", Href = "/organization/settings", CustomIconName = "bi bi-laptop-fill", Text = "Settings", ParentId="70"}, + + new NavItem { Id = "80", IconName = IconName.WindowPlus, Text = "System Administration" }, + new NavItem { Id = "81", Href = "/system-administration/security-users", IconName = IconName.People, Text = "Security Users", ParentId="80"}, + new NavItem { Id = "82", Href = "/system-administration/security-roles", IconName = IconName.PersonRolodex, Text = "Security Roles", ParentId="80"}, + new NavItem { Id = "83", Href = "/system-administration/security-groups", IconName = IconName.CheckAll, Text = "Security Groups", ParentId="80"}, + new NavItem { Id = "84", Href = "/system-administration/audit-logs", IconName = IconName.CheckAll, Text = "Audit Logs", ParentId="80"}, + + new NavItem { Id = "90", Href = "/logout", IconName = IconName.FullscreenExit, Text = "Logout", Match=NavLinkMatch.All}, + + new NavItem { Id = "100", Href = "Account/Login", CustomIconName = "bi bi-person-badge-nav-menu", Text = "Login"}, + + new NavItem { Id = "110", Href = "Account/Register", CustomIconName = "bi bi-person-nav-menu", Text = "Register"}, + + }; + + return navItems; + } +} + diff --git a/src/BlazorGDB/BlazorGDB/Components/Layout/MainLayout.razor.css b/src/BlazorGDB/BlazorGDB/Components/Layout/MainLayout.razor.css new file mode 100644 index 000000000..038baf178 --- /dev/null +++ b/src/BlazorGDB/BlazorGDB/Components/Layout/MainLayout.razor.css @@ -0,0 +1,96 @@ +.page { + position: relative; + display: flex; + flex-direction: column; +} + +main { + flex: 1; +} + +.sidebar { + background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%); +} + +.top-row { + background-color: #f7f7f7; + border-bottom: 1px solid #d6d5d5; + justify-content: flex-end; + height: 3.5rem; + display: flex; + align-items: center; +} + + .top-row ::deep a, .top-row ::deep .btn-link { + white-space: nowrap; + margin-left: 1.5rem; + text-decoration: none; + } + + .top-row ::deep a:hover, .top-row ::deep .btn-link:hover { + text-decoration: underline; + } + + .top-row ::deep a:first-child { + overflow: hidden; + text-overflow: ellipsis; + } + +@media (max-width: 640.98px) { + .top-row { + justify-content: space-between; + } + + .top-row ::deep a, .top-row ::deep .btn-link { + margin-left: 0; + } +} + +@media (min-width: 641px) { + .page { + flex-direction: row; + } + + .sidebar { + width: 250px; + height: 100vh; + position: sticky; + top: 0; + } + + .top-row { + position: sticky; + top: 0; + z-index: 1; + } + + .top-row.auth ::deep a:first-child { + flex: 1; + text-align: right; + width: 0; + } + + .top-row, article { + padding-left: 2rem !important; + padding-right: 1.5rem !important; + } +} + +#blazor-error-ui { + background: lightyellow; + bottom: 0; + box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2); + display: none; + left: 0; + padding: 0.6rem 1.25rem 0.7rem 1.25rem; + position: fixed; + width: 100%; + z-index: 1000; +} + + #blazor-error-ui .dismiss { + cursor: pointer; + position: absolute; + right: 0.75rem; + top: 0.5rem; + } diff --git a/src/BlazorGDB/BlazorGDB/Components/Layout/NavMenu.razor b/src/BlazorGDB/BlazorGDB/Components/Layout/NavMenu.razor new file mode 100644 index 000000000..24628cf73 --- /dev/null +++ b/src/BlazorGDB/BlazorGDB/Components/Layout/NavMenu.razor @@ -0,0 +1,97 @@ +@implements IDisposable + +@inject NavigationManager NavigationManager + + + + + + + +@code { + private string? currentUrl; + + protected override void OnInitialized() + { + currentUrl = NavigationManager.ToBaseRelativePath(NavigationManager.Uri); + NavigationManager.LocationChanged += OnLocationChanged; + } + + private void OnLocationChanged(object? sender, LocationChangedEventArgs e) + { + currentUrl = NavigationManager.ToBaseRelativePath(e.Location); + StateHasChanged(); + } + + public void Dispose() + { + NavigationManager.LocationChanged -= OnLocationChanged; + } +} + diff --git a/src/BlazorGDB/BlazorGDB/Components/Layout/NavMenu.razor.css b/src/BlazorGDB/BlazorGDB/Components/Layout/NavMenu.razor.css new file mode 100644 index 000000000..16700eba7 --- /dev/null +++ b/src/BlazorGDB/BlazorGDB/Components/Layout/NavMenu.razor.css @@ -0,0 +1,125 @@ +.navbar-toggler { + appearance: none; + cursor: pointer; + width: 3.5rem; + height: 2.5rem; + color: white; + position: absolute; + top: 0.5rem; + right: 1rem; + border: 1px solid rgba(255, 255, 255, 0.1); + background: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e") no-repeat center/1.75rem rgba(255, 255, 255, 0.1); +} + +.navbar-toggler:checked { + background-color: rgba(255, 255, 255, 0.5); +} + +.top-row { + height: 3.5rem; + background-color: rgba(0,0,0,0.4); +} + +.navbar-brand { + font-size: 1.1rem; +} + +.bi { + display: inline-block; + position: relative; + width: 1.25rem; + height: 1.25rem; + margin-right: 0.75rem; + top: -1px; + background-size: cover; +} + +.bi-house-door-fill-nav-menu { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-house-door-fill' viewBox='0 0 16 16'%3E%3Cpath d='M6.5 14.5v-3.505c0-.245.25-.495.5-.495h2c.25 0 .5.25.5.5v3.5a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5v-7a.5.5 0 0 0-.146-.354L13 5.793V2.5a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1.293L8.354 1.146a.5.5 0 0 0-.708 0l-6 6A.5.5 0 0 0 1.5 7.5v7a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5Z'/%3E%3C/svg%3E"); +} + +.bi-plus-square-fill-nav-menu { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-plus-square-fill' viewBox='0 0 16 16'%3E%3Cpath d='M2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H2zm6.5 4.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3a.5.5 0 0 1 1 0z'/%3E%3C/svg%3E"); +} + +.bi-list-nested-nav-menu { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-list-nested' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' d='M4.5 11.5A.5.5 0 0 1 5 11h10a.5.5 0 0 1 0 1H5a.5.5 0 0 1-.5-.5zm-2-4A.5.5 0 0 1 3 7h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm-2-4A.5.5 0 0 1 1 3h10a.5.5 0 0 1 0 1H1a.5.5 0 0 1-.5-.5z'/%3E%3C/svg%3E"); +} + +.bi-lock-nav-menu { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-list-nested' viewBox='0 0 16 16'%3E%3Cpath d='M8 1a2 2 0 0 1 2 2v4H6V3a2 2 0 0 1 2-2zm3 6V3a3 3 0 0 0-6 0v4a2 2 0 0 0-2 2v5a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2zM5 8h6a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1V9a1 1 0 0 1 1-1z'/%3E%3C/svg%3E"); +} + +.bi-person-nav-menu { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-person' viewBox='0 0 16 16'%3E%3Cpath d='M8 8a3 3 0 1 0 0-6 3 3 0 0 0 0 6Zm2-3a2 2 0 1 1-4 0 2 2 0 0 1 4 0Zm4 8c0 1-1 1-1 1H3s-1 0-1-1 1-4 6-4 6 3 6 4Zm-1-.004c-.001-.246-.154-.986-.832-1.664C11.516 10.68 10.289 10 8 10c-2.29 0-3.516.68-4.168 1.332-.678.678-.83 1.418-.832 1.664h10Z'/%3E%3C/svg%3E"); +} + +.bi-person-badge-nav-menu { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-person-badge' viewBox='0 0 16 16'%3E%3Cpath d='M6.5 2a.5.5 0 0 0 0 1h3a.5.5 0 0 0 0-1h-3zM11 8a3 3 0 1 1-6 0 3 3 0 0 1 6 0z'/%3E%3Cpath d='M4.5 0A2.5 2.5 0 0 0 2 2.5V14a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V2.5A2.5 2.5 0 0 0 11.5 0h-7zM3 2.5A1.5 1.5 0 0 1 4.5 1h7A1.5 1.5 0 0 1 13 2.5v10.795a4.2 4.2 0 0 0-.776-.492C11.392 12.387 10.063 12 8 12s-3.392.387-4.224.803a4.2 4.2 0 0 0-.776.492V2.5z'/%3E%3C/svg%3E"); +} + +.bi-person-fill-nav-menu { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-person-fill' viewBox='0 0 16 16'%3E%3Cpath d='M3 14s-1 0-1-1 1-4 6-4 6 3 6 4-1 1-1 1H3Zm5-6a3 3 0 1 0 0-6 3 3 0 0 0 0 6Z'/%3E%3C/svg%3E"); +} + +.bi-arrow-bar-left-nav-menu { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-arrow-bar-left' viewBox='0 0 16 16'%3E%3Cpath d='M12.5 15a.5.5 0 0 1-.5-.5v-13a.5.5 0 0 1 1 0v13a.5.5 0 0 1-.5.5ZM10 8a.5.5 0 0 1-.5.5H3.707l2.147 2.146a.5.5 0 0 1-.708.708l-3-3a.5.5 0 0 1 0-.708l3-3a.5.5 0 1 1 .708.708L3.707 7.5H9.5a.5.5 0 0 1 .5.5Z'/%3E%3C/svg%3E"); +} + +.nav-item { + font-size: 0.9rem; + padding-bottom: 0.5rem; +} + + .nav-item:first-of-type { + padding-top: 1rem; + } + + .nav-item:last-of-type { + padding-bottom: 1rem; + } + + .nav-item ::deep .nav-link { + color: #d7d7d7; + background: none; + border: none; + border-radius: 4px; + height: 3rem; + display: flex; + align-items: center; + line-height: 3rem; + width: 100%; + } + +.nav-item ::deep a.active { + background-color: rgba(255,255,255,0.37); + color: white; +} + +.nav-item ::deep .nav-link:hover { + background-color: rgba(255,255,255,0.1); + color: white; +} + +.nav-scrollable { + display: none; +} + +.navbar-toggler:checked ~ .nav-scrollable { + display: block; +} + +@media (min-width: 641px) { + .navbar-toggler { + display: none; + } + + .nav-scrollable { + /* Never collapse the sidebar for wide screens */ + display: block; + + /* Allow sidebar to scroll for tall menus */ + height: calc(100vh - 3.5rem); + overflow-y: auto; + } +} diff --git a/src/BlazorGDB/BlazorGDB/Components/Pages/Error.razor b/src/BlazorGDB/BlazorGDB/Components/Pages/Error.razor new file mode 100644 index 000000000..576cc2d2f --- /dev/null +++ b/src/BlazorGDB/BlazorGDB/Components/Pages/Error.razor @@ -0,0 +1,36 @@ +@page "/Error" +@using System.Diagnostics + +Error + +

    Error.

    +

    An error occurred while processing your request.

    + +@if (ShowRequestId) +{ +

    + Request ID: @RequestId +

    +} + +

    Development Mode

    +

    + Swapping to Development environment will display more detailed information about the error that occurred. +

    +

    + The Development environment shouldn't be enabled for deployed applications. + It can result in displaying sensitive information from exceptions to end users. + For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development + and restarting the app. +

    + +@code{ + [CascadingParameter] + private HttpContext? HttpContext { get; set; } + + private string? RequestId { get; set; } + private bool ShowRequestId => !string.IsNullOrEmpty(RequestId); + + protected override void OnInitialized() => + RequestId = Activity.Current?.Id ?? HttpContext?.TraceIdentifier; +} diff --git a/src/BlazorGDB/BlazorGDB/Components/Pages/Financials/Banks.razor b/src/BlazorGDB/BlazorGDB/Components/Pages/Financials/Banks.razor new file mode 100644 index 000000000..bbd7814a3 --- /dev/null +++ b/src/BlazorGDB/BlazorGDB/Components/Pages/Financials/Banks.razor @@ -0,0 +1,9 @@ +@page "/financials/banks" + +Banks + +

    Banks

    + +@code { + +} diff --git a/src/BlazorGDB/BlazorGDB/Components/Pages/Financials/ChartOfAccounts.razor b/src/BlazorGDB/BlazorGDB/Components/Pages/Financials/ChartOfAccounts.razor new file mode 100644 index 000000000..c8fc84adc --- /dev/null +++ b/src/BlazorGDB/BlazorGDB/Components/Pages/Financials/ChartOfAccounts.razor @@ -0,0 +1,202 @@ +@page "/financials/chart-of-accounts" +@using System.Text.Json +@using System.Text.Json.Serialization +@using LibraryGDB.Models.Financial +@using Microsoft.JSInterop +@using Microsoft.Net.Http.Headers +@inject IHttpClientFactory ClientFactory +@inject Microsoft.JSInterop.IJSRuntime JSRuntime + +Chart of Accounts + +

    Chart Of Accounts

    + +@if (getError || accounts is null) +{ +

    Unable to get data. Please try again later.

    +} +else +{ +@*
      + @foreach (var item in accounts) + { +
    • @item.AccountName
    • + } +
    *@ + + +
    + + + + + + + + + + + + + + @for (int accountIdx = 0; accountIdx < accounts.Count(); ++accountIdx) + { + var account = accounts.ToList()[accountIdx]; + var accountTargetId = $"asset-{accountIdx}"; + + + + + + + + + + + + + } + +
    CodeNameBalanceDebitCredit
    + +
    +
    + +} + +@code { + private IEnumerable? accounts = []; + private bool getError; + private bool shouldRender; + private bool jsInteropCalled = false; // Flag to ensure JS interop is called only once + + + protected override bool ShouldRender() => shouldRender; + + protected override async Task OnInitializedAsync() + { + string apiurl = System.Environment.GetEnvironmentVariable("APIURL") ?? "http://localhost:8001/api/"; + + var request = new HttpRequestMessage(HttpMethod.Get, $"{apiurl}financials/accounts"); + request.Headers.Add("Accept", "application/json"); + + var _client = ClientFactory.CreateClient(); + + _client.DefaultRequestHeaders.Accept.Clear(); + _client.DefaultRequestHeaders.Clear(); + _client.DefaultRequestHeaders.CacheControl = new System.Net.Http.Headers.CacheControlHeaderValue() { NoCache = true }; + _client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json")); + + var response = await _client.SendAsync(request).ConfigureAwait(false); + + if (response.IsSuccessStatusCode) + { + var responseString = await response.Content.ReadAsStringAsync(); + + // Log the response string to verify the JSON structure + // Console.WriteLine($"Response JSON: {responseString}"); + + // Ensure JsonSerializerOptions are set correctly + var options = new JsonSerializerOptions + { + PropertyNameCaseInsensitive = true, // Adjust based on your JSON + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, + }; + + try + { + accounts = JsonSerializer.Deserialize>(responseString, options); + } + catch (JsonException ex) + { + // Log the exception to diagnose deserialization issues + Console.WriteLine($"JSON Deserialization error: {ex.Message}"); + getError = true; + } + + // await JSRuntime.InvokeVoidAsync("console.log", accounts); + } + else + { + getError = true; + } + + shouldRender = true; + } + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (firstRender && !jsInteropCalled) + { + await JSRuntime.InvokeVoidAsync("console.log", accounts); + jsInteropCalled = true; // Ensure this block runs only once + } + } +} diff --git a/src/BlazorGDB/BlazorGDB/Components/Pages/Financials/GeneralLedgers.razor b/src/BlazorGDB/BlazorGDB/Components/Pages/Financials/GeneralLedgers.razor new file mode 100644 index 000000000..6a19d7c22 --- /dev/null +++ b/src/BlazorGDB/BlazorGDB/Components/Pages/Financials/GeneralLedgers.razor @@ -0,0 +1,9 @@ +@page "/financials/general-ledgers" + +General Ledgers + +

    General Ledgers

    + +@code { + +} diff --git a/src/BlazorGDB/BlazorGDB/Components/Pages/Financials/JournalEntries.razor b/src/BlazorGDB/BlazorGDB/Components/Pages/Financials/JournalEntries.razor new file mode 100644 index 000000000..a7178b364 --- /dev/null +++ b/src/BlazorGDB/BlazorGDB/Components/Pages/Financials/JournalEntries.razor @@ -0,0 +1,9 @@ +@page "/financials/journal-entries" + +Journal Entries + +

    Journal Entries

    + +@code { + +} diff --git a/src/BlazorGDB/BlazorGDB/Components/Pages/Financials/Taxes.razor b/src/BlazorGDB/BlazorGDB/Components/Pages/Financials/Taxes.razor new file mode 100644 index 000000000..08f88ada0 --- /dev/null +++ b/src/BlazorGDB/BlazorGDB/Components/Pages/Financials/Taxes.razor @@ -0,0 +1,9 @@ +@page "/financials/taxes" + +Taxes + +

    Taxes

    + +@code { + +} diff --git a/src/BlazorGDB/BlazorGDB/Components/Pages/Home.razor b/src/BlazorGDB/BlazorGDB/Components/Pages/Home.razor new file mode 100644 index 000000000..9001e0bd2 --- /dev/null +++ b/src/BlazorGDB/BlazorGDB/Components/Pages/Home.razor @@ -0,0 +1,7 @@ +@page "/" + +Home + +

    Hello, world!

    + +Welcome to your new app. diff --git a/src/BlazorGDB/BlazorGDB/Components/Pages/Inventory/InventoryControlJournal.razor b/src/BlazorGDB/BlazorGDB/Components/Pages/Inventory/InventoryControlJournal.razor new file mode 100644 index 000000000..39ab6ce12 --- /dev/null +++ b/src/BlazorGDB/BlazorGDB/Components/Pages/Inventory/InventoryControlJournal.razor @@ -0,0 +1,9 @@ +@page "/inventory/inventory-control-journal" + +Inventory Control Journal + +

    Inventory Control Journal

    + +@code { + +} diff --git a/src/BlazorGDB/BlazorGDB/Components/Pages/Inventory/Items.razor b/src/BlazorGDB/BlazorGDB/Components/Pages/Inventory/Items.razor new file mode 100644 index 000000000..e02eea7c4 --- /dev/null +++ b/src/BlazorGDB/BlazorGDB/Components/Pages/Inventory/Items.razor @@ -0,0 +1,9 @@ +@page "/inventory/items" + +Items + +

    Items

    + +@code { + +} diff --git a/src/BlazorGDB/BlazorGDB/Components/Pages/Organization/Company.razor b/src/BlazorGDB/BlazorGDB/Components/Pages/Organization/Company.razor new file mode 100644 index 000000000..9d59cf08b --- /dev/null +++ b/src/BlazorGDB/BlazorGDB/Components/Pages/Organization/Company.razor @@ -0,0 +1,9 @@ +@page "/organization/company" + +Company + +

    Company

    + +@code { + +} diff --git a/src/BlazorGDB/BlazorGDB/Components/Pages/Organization/Settings.razor b/src/BlazorGDB/BlazorGDB/Components/Pages/Organization/Settings.razor new file mode 100644 index 000000000..fabf58a68 --- /dev/null +++ b/src/BlazorGDB/BlazorGDB/Components/Pages/Organization/Settings.razor @@ -0,0 +1,9 @@ +@page "/organization/settings" + +Settings + +

    Settings

    + +@code { + +} diff --git a/src/BlazorGDB/BlazorGDB/Components/Pages/Payables/PurchaseInvoices.razor b/src/BlazorGDB/BlazorGDB/Components/Pages/Payables/PurchaseInvoices.razor new file mode 100644 index 000000000..0c76e5ad0 --- /dev/null +++ b/src/BlazorGDB/BlazorGDB/Components/Pages/Payables/PurchaseInvoices.razor @@ -0,0 +1,9 @@ +@page "/payables/purchase-invoices" + +Purchase Invoices + +

    Purchase Invoices

    + +@code { + +} diff --git a/src/BlazorGDB/BlazorGDB/Components/Pages/Payables/PurchaseOrders.razor b/src/BlazorGDB/BlazorGDB/Components/Pages/Payables/PurchaseOrders.razor new file mode 100644 index 000000000..5caef6984 --- /dev/null +++ b/src/BlazorGDB/BlazorGDB/Components/Pages/Payables/PurchaseOrders.razor @@ -0,0 +1,9 @@ +@page "/payables/purchase-orders" + +Purchase Orders + +

    Purchase Orders

    + +@code { + +} diff --git a/src/BlazorGDB/BlazorGDB/Components/Pages/Payables/Vendors.razor b/src/BlazorGDB/BlazorGDB/Components/Pages/Payables/Vendors.razor new file mode 100644 index 000000000..f335518e3 --- /dev/null +++ b/src/BlazorGDB/BlazorGDB/Components/Pages/Payables/Vendors.razor @@ -0,0 +1,9 @@ +@page "/payables/vendors" + +Vendors + +

    Vendors

    + +@code { + +} diff --git a/src/BlazorGDB/BlazorGDB/Components/Pages/Receivables/Customers.razor b/src/BlazorGDB/BlazorGDB/Components/Pages/Receivables/Customers.razor new file mode 100644 index 000000000..76814cec6 --- /dev/null +++ b/src/BlazorGDB/BlazorGDB/Components/Pages/Receivables/Customers.razor @@ -0,0 +1,9 @@ +@page "/receivables/customers" + +Customers + +

    Customers

    + +@code { + +} diff --git a/src/BlazorGDB/BlazorGDB/Components/Pages/Receivables/DonationInvoices.razor b/src/BlazorGDB/BlazorGDB/Components/Pages/Receivables/DonationInvoices.razor new file mode 100644 index 000000000..721081500 --- /dev/null +++ b/src/BlazorGDB/BlazorGDB/Components/Pages/Receivables/DonationInvoices.razor @@ -0,0 +1,9 @@ +@page "/receivables/donation-invoices" + +Donation Invoices + +

    Donation Invoices

    + +@code { + +} diff --git a/src/BlazorGDB/BlazorGDB/Components/Pages/Receivables/SalesInvoices.razor b/src/BlazorGDB/BlazorGDB/Components/Pages/Receivables/SalesInvoices.razor new file mode 100644 index 000000000..4daf2abc1 --- /dev/null +++ b/src/BlazorGDB/BlazorGDB/Components/Pages/Receivables/SalesInvoices.razor @@ -0,0 +1,9 @@ +@page "/receivables/sales-invoices" + +Sales Invoices + +

    Sales Invoices

    + +@code { + +} diff --git a/src/BlazorGDB/BlazorGDB/Components/Pages/Receivables/SalesOrders.razor b/src/BlazorGDB/BlazorGDB/Components/Pages/Receivables/SalesOrders.razor new file mode 100644 index 000000000..525387a67 --- /dev/null +++ b/src/BlazorGDB/BlazorGDB/Components/Pages/Receivables/SalesOrders.razor @@ -0,0 +1,9 @@ +@page "/receivables/sales-orders" + +Sales Orders + +

    Sales Orders

    + +@code { + +} diff --git a/src/BlazorGDB/BlazorGDB/Components/Pages/Receivables/SalesQuotations.razor b/src/BlazorGDB/BlazorGDB/Components/Pages/Receivables/SalesQuotations.razor new file mode 100644 index 000000000..ecb084eab --- /dev/null +++ b/src/BlazorGDB/BlazorGDB/Components/Pages/Receivables/SalesQuotations.razor @@ -0,0 +1,14 @@ +@page "/receivables/sales-quotations" + +Sales Quotations + +

    Sales Quotations

    + + + Dropdown button + + Action + Another action + Something else here + + \ No newline at end of file diff --git a/src/BlazorGDB/BlazorGDB/Components/Pages/Receivables/SalesReceipts.razor b/src/BlazorGDB/BlazorGDB/Components/Pages/Receivables/SalesReceipts.razor new file mode 100644 index 000000000..1a8df302b --- /dev/null +++ b/src/BlazorGDB/BlazorGDB/Components/Pages/Receivables/SalesReceipts.razor @@ -0,0 +1,9 @@ +@page "/receivables/sales-receipts" + +Sales Receipts + +

    Sales Receipts

    + +@code { + +} diff --git a/src/BlazorGDB/BlazorGDB/Components/Pages/Reports/BalanceSheet.razor b/src/BlazorGDB/BlazorGDB/Components/Pages/Reports/BalanceSheet.razor new file mode 100644 index 000000000..1f0915221 --- /dev/null +++ b/src/BlazorGDB/BlazorGDB/Components/Pages/Reports/BalanceSheet.razor @@ -0,0 +1,9 @@ +@page "/reports/balance-sheet" + +Balance Sheet + +

    Balance Sheet

    + +@code { + +} diff --git a/src/BlazorGDB/BlazorGDB/Components/Pages/Reports/IncomeStatement.razor b/src/BlazorGDB/BlazorGDB/Components/Pages/Reports/IncomeStatement.razor new file mode 100644 index 000000000..7df1555f3 --- /dev/null +++ b/src/BlazorGDB/BlazorGDB/Components/Pages/Reports/IncomeStatement.razor @@ -0,0 +1,9 @@ +@page "/reports/income-statement" + +Income Statement + +

    Income Statement

    + +@code { + +} diff --git a/src/BlazorGDB/BlazorGDB/Components/Pages/Reports/TrialBalance.razor b/src/BlazorGDB/BlazorGDB/Components/Pages/Reports/TrialBalance.razor new file mode 100644 index 000000000..358cbc301 --- /dev/null +++ b/src/BlazorGDB/BlazorGDB/Components/Pages/Reports/TrialBalance.razor @@ -0,0 +1,9 @@ +@page "/reports/trial-balance" + +Trial Balance + +

    Trial Balance

    + +@code { + +} diff --git a/src/BlazorGDB/BlazorGDB/Components/Pages/SystemAdministration/AuditLogs.razor b/src/BlazorGDB/BlazorGDB/Components/Pages/SystemAdministration/AuditLogs.razor new file mode 100644 index 000000000..ae3396075 --- /dev/null +++ b/src/BlazorGDB/BlazorGDB/Components/Pages/SystemAdministration/AuditLogs.razor @@ -0,0 +1,9 @@ +@page "/system-administration/audit-logs" + +Audit Logs + +

    Audit Logs

    + +@code { + +} diff --git a/src/BlazorGDB/BlazorGDB/Components/Pages/SystemAdministration/SecurityGroups.razor b/src/BlazorGDB/BlazorGDB/Components/Pages/SystemAdministration/SecurityGroups.razor new file mode 100644 index 000000000..1c39e97f3 --- /dev/null +++ b/src/BlazorGDB/BlazorGDB/Components/Pages/SystemAdministration/SecurityGroups.razor @@ -0,0 +1,9 @@ +@page "/system-administration/security-groups" + +Security Groups + +

    Security Groups

    + +@code { + +} diff --git a/src/BlazorGDB/BlazorGDB/Components/Pages/SystemAdministration/SecurityRoles.razor b/src/BlazorGDB/BlazorGDB/Components/Pages/SystemAdministration/SecurityRoles.razor new file mode 100644 index 000000000..f1ebce518 --- /dev/null +++ b/src/BlazorGDB/BlazorGDB/Components/Pages/SystemAdministration/SecurityRoles.razor @@ -0,0 +1,9 @@ +@page "/system-administration/security-roles" + +Security Roles + +

    Security Roles

    + +@code { + +} diff --git a/src/BlazorGDB/BlazorGDB/Components/Pages/SystemAdministration/SecurityUsers.razor b/src/BlazorGDB/BlazorGDB/Components/Pages/SystemAdministration/SecurityUsers.razor new file mode 100644 index 000000000..36a938a5d --- /dev/null +++ b/src/BlazorGDB/BlazorGDB/Components/Pages/SystemAdministration/SecurityUsers.razor @@ -0,0 +1,9 @@ +@page "/system-administration/security-users" + +Security Users + +

    Security Users

    + +@code { + +} diff --git a/src/BlazorGDB/BlazorGDB/Components/Pages/Weather.razor b/src/BlazorGDB/BlazorGDB/Components/Pages/Weather.razor new file mode 100644 index 000000000..43a1ecbe9 --- /dev/null +++ b/src/BlazorGDB/BlazorGDB/Components/Pages/Weather.razor @@ -0,0 +1,64 @@ +@page "/weather" +@attribute [StreamRendering] + +Weather + +

    Weather

    + +

    This component demonstrates showing data.

    + +@if (forecasts == null) +{ +

    Loading...

    +} +else +{ + + + + + + + + + + + @foreach (var forecast in forecasts) + { + + + + + + + } + +
    DateTemp. (C)Temp. (F)Summary
    @forecast.Date.ToShortDateString()@forecast.TemperatureC@forecast.TemperatureF@forecast.Summary
    +} + +@code { + private WeatherForecast[]? forecasts; + + protected override async Task OnInitializedAsync() + { + // Simulate asynchronous loading to demonstrate streaming rendering + await Task.Delay(500); + + var startDate = DateOnly.FromDateTime(DateTime.Now); + var summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" }; + forecasts = Enumerable.Range(1, 5).Select(index => new WeatherForecast + { + Date = startDate.AddDays(index), + TemperatureC = Random.Shared.Next(-20, 55), + Summary = summaries[Random.Shared.Next(summaries.Length)] + }).ToArray(); + } + + private class WeatherForecast + { + public DateOnly Date { get; set; } + public int TemperatureC { get; set; } + public string? Summary { get; set; } + public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); + } +} diff --git a/src/BlazorGDB/BlazorGDB/Components/Routes.razor b/src/BlazorGDB/BlazorGDB/Components/Routes.razor new file mode 100644 index 000000000..c3758f3a9 --- /dev/null +++ b/src/BlazorGDB/BlazorGDB/Components/Routes.razor @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/BlazorGDB/BlazorGDB/Components/_Imports.razor b/src/BlazorGDB/BlazorGDB/Components/_Imports.razor new file mode 100644 index 000000000..9b1b0871d --- /dev/null +++ b/src/BlazorGDB/BlazorGDB/Components/_Imports.razor @@ -0,0 +1,15 @@ +@using System.Net.Http +@using System.Net.Http.Json +@using Microsoft.AspNetCore.Components.Authorization +@using Microsoft.AspNetCore.Components.Forms +@using Microsoft.AspNetCore.Components.Routing +@using Microsoft.AspNetCore.Components.Web +@using static Microsoft.AspNetCore.Components.Web.RenderMode +@using Microsoft.AspNetCore.Components.Web.Virtualization +@using Microsoft.JSInterop +@using BlazorGDB +@using BlazorGDB.Client +@using BlazorGDB.Components +@using LibraryGDB.Models +@using BlazorBootstrap; + diff --git a/src/BlazorGDB/BlazorGDB/Data/ApplicationDbContext.cs b/src/BlazorGDB/BlazorGDB/Data/ApplicationDbContext.cs new file mode 100644 index 000000000..ac7533e71 --- /dev/null +++ b/src/BlazorGDB/BlazorGDB/Data/ApplicationDbContext.cs @@ -0,0 +1,8 @@ +using Microsoft.AspNetCore.Identity.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore; + +namespace BlazorGDB.Data; + +public class ApplicationDbContext(DbContextOptions options) : IdentityDbContext(options) +{ +} diff --git a/src/BlazorGDB/BlazorGDB/Data/ApplicationUser.cs b/src/BlazorGDB/BlazorGDB/Data/ApplicationUser.cs new file mode 100644 index 000000000..d09b151cd --- /dev/null +++ b/src/BlazorGDB/BlazorGDB/Data/ApplicationUser.cs @@ -0,0 +1,9 @@ +using Microsoft.AspNetCore.Identity; + +namespace BlazorGDB.Data; + +// Add profile data for application users by adding properties to the ApplicationUser class +public class ApplicationUser : IdentityUser +{ +} + diff --git a/src/BlazorGDB/BlazorGDB/Data/Migrations/00000000000000_CreateIdentitySchema.Designer.cs b/src/BlazorGDB/BlazorGDB/Data/Migrations/00000000000000_CreateIdentitySchema.Designer.cs new file mode 100644 index 000000000..9bd5930b3 --- /dev/null +++ b/src/BlazorGDB/BlazorGDB/Data/Migrations/00000000000000_CreateIdentitySchema.Designer.cs @@ -0,0 +1,268 @@ +// +using System; +using BlazorGDB.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace BlazorGDB.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + [Migration("00000000000000_CreateIdentitySchema")] + partial class CreateIdentitySchema + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "8.0.0"); + + modelBuilder.Entity("BlazorGDB.Data.ApplicationUser", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("AccessFailedCount") + .HasColumnType("INTEGER"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("EmailConfirmed") + .HasColumnType("INTEGER"); + + b.Property("LockoutEnabled") + .HasColumnType("INTEGER"); + + b.Property("LockoutEnd") + .HasColumnType("TEXT"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("PasswordHash") + .HasColumnType("TEXT"); + + b.Property("PhoneNumber") + .HasColumnType("TEXT"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("INTEGER"); + + b.Property("SecurityStamp") + .HasColumnType("TEXT"); + + b.Property("TwoFactorEnabled") + .HasColumnType("INTEGER"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("ProviderKey") + .HasColumnType("TEXT"); + + b.Property("ProviderDisplayName") + .HasColumnType("TEXT"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .HasColumnType("TEXT"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("BlazorGDB.Data.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("BlazorGDB.Data.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("BlazorGDB.Data.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("BlazorGDB.Data.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/BlazorGDB/BlazorGDB/Data/Migrations/00000000000000_CreateIdentitySchema.cs b/src/BlazorGDB/BlazorGDB/Data/Migrations/00000000000000_CreateIdentitySchema.cs new file mode 100644 index 000000000..34d5f4eb5 --- /dev/null +++ b/src/BlazorGDB/BlazorGDB/Data/Migrations/00000000000000_CreateIdentitySchema.cs @@ -0,0 +1,222 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace BlazorGDB.Migrations +{ + /// + public partial class CreateIdentitySchema : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "AspNetRoles", + columns: table => new + { + Id = table.Column(type: "TEXT", nullable: false), + Name = table.Column(type: "TEXT", maxLength: 256, nullable: true), + NormalizedName = table.Column(type: "TEXT", maxLength: 256, nullable: true), + ConcurrencyStamp = table.Column(type: "TEXT", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetRoles", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AspNetUsers", + columns: table => new + { + Id = table.Column(type: "TEXT", nullable: false), + UserName = table.Column(type: "TEXT", maxLength: 256, nullable: true), + NormalizedUserName = table.Column(type: "TEXT", maxLength: 256, nullable: true), + Email = table.Column(type: "TEXT", maxLength: 256, nullable: true), + NormalizedEmail = table.Column(type: "TEXT", maxLength: 256, nullable: true), + EmailConfirmed = table.Column(type: "INTEGER", nullable: false), + PasswordHash = table.Column(type: "TEXT", nullable: true), + SecurityStamp = table.Column(type: "TEXT", nullable: true), + ConcurrencyStamp = table.Column(type: "TEXT", nullable: true), + PhoneNumber = table.Column(type: "TEXT", nullable: true), + PhoneNumberConfirmed = table.Column(type: "INTEGER", nullable: false), + TwoFactorEnabled = table.Column(type: "INTEGER", nullable: false), + LockoutEnd = table.Column(type: "TEXT", nullable: true), + LockoutEnabled = table.Column(type: "INTEGER", nullable: false), + AccessFailedCount = table.Column(type: "INTEGER", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetUsers", x => x.Id); + }); + + migrationBuilder.CreateTable( + name: "AspNetRoleClaims", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + RoleId = table.Column(type: "TEXT", nullable: false), + ClaimType = table.Column(type: "TEXT", nullable: true), + ClaimValue = table.Column(type: "TEXT", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetRoleClaims", x => x.Id); + table.ForeignKey( + name: "FK_AspNetRoleClaims_AspNetRoles_RoleId", + column: x => x.RoleId, + principalTable: "AspNetRoles", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AspNetUserClaims", + columns: table => new + { + Id = table.Column(type: "INTEGER", nullable: false) + .Annotation("Sqlite:Autoincrement", true), + UserId = table.Column(type: "TEXT", nullable: false), + ClaimType = table.Column(type: "TEXT", nullable: true), + ClaimValue = table.Column(type: "TEXT", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetUserClaims", x => x.Id); + table.ForeignKey( + name: "FK_AspNetUserClaims_AspNetUsers_UserId", + column: x => x.UserId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AspNetUserLogins", + columns: table => new + { + LoginProvider = table.Column(type: "TEXT", nullable: false), + ProviderKey = table.Column(type: "TEXT", nullable: false), + ProviderDisplayName = table.Column(type: "TEXT", nullable: true), + UserId = table.Column(type: "TEXT", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetUserLogins", x => new { x.LoginProvider, x.ProviderKey }); + table.ForeignKey( + name: "FK_AspNetUserLogins_AspNetUsers_UserId", + column: x => x.UserId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AspNetUserRoles", + columns: table => new + { + UserId = table.Column(type: "TEXT", nullable: false), + RoleId = table.Column(type: "TEXT", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetUserRoles", x => new { x.UserId, x.RoleId }); + table.ForeignKey( + name: "FK_AspNetUserRoles_AspNetRoles_RoleId", + column: x => x.RoleId, + principalTable: "AspNetRoles", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_AspNetUserRoles_AspNetUsers_UserId", + column: x => x.UserId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "AspNetUserTokens", + columns: table => new + { + UserId = table.Column(type: "TEXT", nullable: false), + LoginProvider = table.Column(type: "TEXT", nullable: false), + Name = table.Column(type: "TEXT", nullable: false), + Value = table.Column(type: "TEXT", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_AspNetUserTokens", x => new { x.UserId, x.LoginProvider, x.Name }); + table.ForeignKey( + name: "FK_AspNetUserTokens_AspNetUsers_UserId", + column: x => x.UserId, + principalTable: "AspNetUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_AspNetRoleClaims_RoleId", + table: "AspNetRoleClaims", + column: "RoleId"); + + migrationBuilder.CreateIndex( + name: "RoleNameIndex", + table: "AspNetRoles", + column: "NormalizedName", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_AspNetUserClaims_UserId", + table: "AspNetUserClaims", + column: "UserId"); + + migrationBuilder.CreateIndex( + name: "IX_AspNetUserLogins_UserId", + table: "AspNetUserLogins", + column: "UserId"); + + migrationBuilder.CreateIndex( + name: "IX_AspNetUserRoles_RoleId", + table: "AspNetUserRoles", + column: "RoleId"); + + migrationBuilder.CreateIndex( + name: "EmailIndex", + table: "AspNetUsers", + column: "NormalizedEmail"); + + migrationBuilder.CreateIndex( + name: "UserNameIndex", + table: "AspNetUsers", + column: "NormalizedUserName", + unique: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "AspNetRoleClaims"); + + migrationBuilder.DropTable( + name: "AspNetUserClaims"); + + migrationBuilder.DropTable( + name: "AspNetUserLogins"); + + migrationBuilder.DropTable( + name: "AspNetUserRoles"); + + migrationBuilder.DropTable( + name: "AspNetUserTokens"); + + migrationBuilder.DropTable( + name: "AspNetRoles"); + + migrationBuilder.DropTable( + name: "AspNetUsers"); + } + } +} diff --git a/src/BlazorGDB/BlazorGDB/Data/Migrations/ApplicationDbContextModelSnapshot.cs b/src/BlazorGDB/BlazorGDB/Data/Migrations/ApplicationDbContextModelSnapshot.cs new file mode 100644 index 000000000..296626da8 --- /dev/null +++ b/src/BlazorGDB/BlazorGDB/Data/Migrations/ApplicationDbContextModelSnapshot.cs @@ -0,0 +1,265 @@ +// +using System; +using BlazorGDB.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace BlazorGDB.Migrations +{ + [DbContext(typeof(ApplicationDbContext))] + partial class ApplicationDbContextModelSnapshot : ModelSnapshot + { + protected override void BuildModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "8.0.0"); + + modelBuilder.Entity("BlazorGDB.Data.ApplicationUser", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("AccessFailedCount") + .HasColumnType("INTEGER"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("EmailConfirmed") + .HasColumnType("INTEGER"); + + b.Property("LockoutEnabled") + .HasColumnType("INTEGER"); + + b.Property("LockoutEnd") + .HasColumnType("TEXT"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("PasswordHash") + .HasColumnType("TEXT"); + + b.Property("PhoneNumber") + .HasColumnType("TEXT"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("INTEGER"); + + b.Property("SecurityStamp") + .HasColumnType("TEXT"); + + b.Property("TwoFactorEnabled") + .HasColumnType("INTEGER"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("TEXT"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("TEXT"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("ClaimType") + .HasColumnType("TEXT"); + + b.Property("ClaimValue") + .HasColumnType("TEXT"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("ProviderKey") + .HasColumnType("TEXT"); + + b.Property("ProviderDisplayName") + .HasColumnType("TEXT"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("RoleId") + .HasColumnType("TEXT"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("TEXT"); + + b.Property("LoginProvider") + .HasColumnType("TEXT"); + + b.Property("Name") + .HasColumnType("TEXT"); + + b.Property("Value") + .HasColumnType("TEXT"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("BlazorGDB.Data.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("BlazorGDB.Data.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("BlazorGDB.Data.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("BlazorGDB.Data.ApplicationUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/BlazorGDB/BlazorGDB/Data/app.db b/src/BlazorGDB/BlazorGDB/Data/app.db new file mode 100644 index 000000000..769de58a9 Binary files /dev/null and b/src/BlazorGDB/BlazorGDB/Data/app.db differ diff --git a/src/BlazorGDB/BlazorGDB/Program.cs b/src/BlazorGDB/BlazorGDB/Program.cs new file mode 100644 index 000000000..7cf3c777e --- /dev/null +++ b/src/BlazorGDB/BlazorGDB/Program.cs @@ -0,0 +1,83 @@ +using Microsoft.AspNetCore.Components.Authorization; +using Microsoft.AspNetCore.Identity; +using Microsoft.EntityFrameworkCore; +using BlazorGDB.Components; +using BlazorGDB.Components.Account; +using BlazorGDB.Data; + +var builder = WebApplication.CreateBuilder(args); + +// Add services to the container. +builder.Services.AddRazorComponents() + .AddInteractiveServerComponents() + .AddInteractiveWebAssemblyComponents(); + +builder.Services.AddCascadingAuthenticationState(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); +builder.Services.AddScoped(); + +builder.Services.AddAuthentication(options => + { + options.DefaultScheme = IdentityConstants.ApplicationScheme; + options.DefaultSignInScheme = IdentityConstants.ExternalScheme; + }) + .AddIdentityCookies(); + +var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found."); +builder.Services.AddDbContext(options => + options.UseSqlite(connectionString)); +builder.Services.AddDatabaseDeveloperPageExceptionFilter(); + +builder.Services.AddIdentityCore(options => options.SignIn.RequireConfirmedAccount = true) + .AddEntityFrameworkStores() + .AddSignInManager() + .AddDefaultTokenProviders(); + +builder.Services.AddSingleton, IdentityNoOpEmailSender>(); + +builder.Services.AddBlazorBootstrap(); + +// Register IHttpClientFactory +builder.Services.AddHttpClient(); + +var app = builder.Build(); + +// Configure the HTTP request pipeline. +if (app.Environment.IsDevelopment()) +{ + app.UseWebAssemblyDebugging(); + app.UseMigrationsEndPoint(); +} +else +{ + app.UseExceptionHandler("/Error", createScopeForErrors: true); + // 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.UseAntiforgery(); + +app.MapRazorComponents() + .AddInteractiveServerRenderMode() + .AddInteractiveWebAssemblyRenderMode() + .AddAdditionalAssemblies(typeof(BlazorGDB.Client._Imports).Assembly); + +// Add additional endpoints required by the Identity /Account Razor components. +app.MapAdditionalIdentityEndpoints(); + +using (var scope = app.Services.CreateScope()) +{ + var services = scope.ServiceProvider; + + var dbContext = services.GetRequiredService(); + if (!dbContext.Database.GetAppliedMigrations().Any()) + { + dbContext.Database.Migrate(); + } +} + +app.Run(); diff --git a/src/BlazorGDB/BlazorGDB/Properties/launchSettings.json b/src/BlazorGDB/BlazorGDB/Properties/launchSettings.json new file mode 100644 index 000000000..a5c7a5f8a --- /dev/null +++ b/src/BlazorGDB/BlazorGDB/Properties/launchSettings.json @@ -0,0 +1,41 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:63910", + "sslPort": 44371 + } + }, + "profiles": { + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", + "applicationUrl": "http://localhost:5239", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", + "applicationUrl": "https://localhost:7086;http://localhost:5239", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } + } diff --git a/src/BlazorGDB/BlazorGDB/appsettings.Development.json b/src/BlazorGDB/BlazorGDB/appsettings.Development.json new file mode 100644 index 000000000..0c208ae91 --- /dev/null +++ b/src/BlazorGDB/BlazorGDB/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/src/BlazorGDB/BlazorGDB/appsettings.json b/src/BlazorGDB/BlazorGDB/appsettings.json new file mode 100644 index 000000000..815f55ff7 --- /dev/null +++ b/src/BlazorGDB/BlazorGDB/appsettings.json @@ -0,0 +1,12 @@ +{ + "ConnectionStrings": { + "DefaultConnection": "DataSource=good-deed-books.db;Cache=Shared" + }, + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/src/BlazorGDB/BlazorGDB/good-deed-books.db b/src/BlazorGDB/BlazorGDB/good-deed-books.db new file mode 100644 index 000000000..9ad090262 Binary files /dev/null and b/src/BlazorGDB/BlazorGDB/good-deed-books.db differ diff --git a/src/BlazorGDB/BlazorGDB/wwwroot/app.css b/src/BlazorGDB/BlazorGDB/wwwroot/app.css new file mode 100644 index 000000000..2bd9b7896 --- /dev/null +++ b/src/BlazorGDB/BlazorGDB/wwwroot/app.css @@ -0,0 +1,51 @@ +html, body { + font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; +} + +a, .btn-link { + color: #006bb7; +} + +.btn-primary { + color: #fff; + background-color: #1b6ec2; + border-color: #1861ac; +} + +.btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus { + box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb; +} + +.content { + padding-top: 1.1rem; +} + +h1:focus { + outline: none; +} + +.valid.modified:not([type=checkbox]) { + outline: 1px solid #26b050; +} + +.invalid { + outline: 1px solid #e50000; +} + +.validation-message { + color: #e50000; +} + +.blazor-error-boundary { + background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121; + padding: 1rem 1rem 1rem 3.7rem; + color: white; +} + + .blazor-error-boundary::after { + content: "An error has occurred." + } + +.darker-border-checkbox.form-check-input { + border-color: #929292; +} diff --git a/src/BlazorGDB/BlazorGDB/wwwroot/favicon.png b/src/BlazorGDB/BlazorGDB/wwwroot/favicon.png new file mode 100644 index 000000000..8422b5969 Binary files /dev/null and b/src/BlazorGDB/BlazorGDB/wwwroot/favicon.png differ diff --git a/src/Core/Core.csproj b/src/Core/Core.csproj index a0aec9e66..d28f66c13 100644 --- a/src/Core/Core.csproj +++ b/src/Core/Core.csproj @@ -1,12 +1,6 @@  - - netstandard2.1 + net9.0 Library - - - - - \ No newline at end of file diff --git a/src/Core/Data/IRepository.cs b/src/Core/Data/IRepository.cs index b3b453a43..00a8eb498 100644 --- a/src/Core/Data/IRepository.cs +++ b/src/Core/Data/IRepository.cs @@ -11,6 +11,8 @@ namespace Core.Data using Domain; using System; using System.Linq; + using System.Threading.Tasks; + /// /// Repository /// @@ -18,8 +20,11 @@ public partial interface IRepository where T : BaseEntity { T GetById(object id); void Insert(T entity); + Task InsertAsync(T entity); void Update(T entity); + Task UpdateAsync(T enitity); void Delete(T entity); + Task DeleteAsync(T entity); IQueryable Table { get; } IQueryable GetAllIncluding(params System.Linq.Expressions.Expression>[] includeProperties); diff --git a/src/Core/Domain/Company.cs b/src/Core/Domain/Company.cs index 4b9b00a37..e543c3d9b 100644 --- a/src/Core/Domain/Company.cs +++ b/src/Core/Domain/Company.cs @@ -17,5 +17,6 @@ public partial class Company : BaseEntity public string Name { get; set; } public string ShortName { get; set; } public string CompanyCode { get; set; } + public string CRA { get; set; } } } diff --git a/src/Core/Domain/Error/Error.cs b/src/Core/Domain/Error/Error.cs new file mode 100644 index 000000000..74031e204 --- /dev/null +++ b/src/Core/Domain/Error/Error.cs @@ -0,0 +1,12 @@ +namespace Core.Domain.Error +{ + public sealed record Error(string Code, string Message) + { + private static readonly string RecordNotFoundCode = "RecordNotFound"; + private static readonly string ValidationErrorCode = "ValidationError"; + + public static readonly Error None = new(string.Empty, string.Empty); + public static Error RecordNotFound(string message) => new Error(RecordNotFoundCode, message); + public static Error ValidationError(string message) => new Error(ValidationErrorCode, message); + } +} diff --git a/src/Core/Domain/Error/Result.cs b/src/Core/Domain/Error/Result.cs new file mode 100644 index 000000000..305ce2cc7 --- /dev/null +++ b/src/Core/Domain/Error/Result.cs @@ -0,0 +1,49 @@ +using System; +using System.Reflection.Metadata.Ecma335; + +namespace Core.Domain.Error +{ + public class Result where T : class + { + private readonly T? _value; + + private Result(T value) + { + Value = value; + IsSuccess = true; + Error = Error.None; + } + + private Result(Error error) + { + if (error == Error.None) + { + throw new ArgumentException("invalid error", nameof(error)); + } + + IsSuccess = false; + Error = error; + } + + public bool IsSuccess { get; } + public bool IsFailure => !IsSuccess; + + public T Value + { + get + { + if (IsFailure) + { + throw new InvalidOperationException("There is no value for failure result. Use 'Error' property instead."); + } + + return _value!; + } + private init => _value = value; + } + + public Error Error { get; } + public static Result Success(T value) => new Result(value); + public static Result Failure(Error error) => new Result(error); + } +} diff --git a/src/Core/Domain/Financials/Account.cs b/src/Core/Domain/Financials/Account.cs index 7385ec215..5b9a2a6a1 100644 --- a/src/Core/Domain/Financials/Account.cs +++ b/src/Core/Domain/Financials/Account.cs @@ -46,7 +46,7 @@ public Account() public virtual Company Company { get; set; } public virtual ICollection ChildAccounts { get; set; } - [NotMapped] + // [NotMapped] public virtual ICollection ContraAccounts { get; set; } public virtual ICollection GeneralLedgerLines { get; set; } diff --git a/src/Core/Domain/Sales/SalesReceiptLine.cs b/src/Core/Domain/Sales/SalesReceiptLine.cs index 30ff71055..571c93f38 100644 --- a/src/Core/Domain/Sales/SalesReceiptLine.cs +++ b/src/Core/Domain/Sales/SalesReceiptLine.cs @@ -7,6 +7,7 @@ //----------------------------------------------------------------------- using Core.Domain.Financials; +using Core.Domain.Items; using System; using System.Linq; using System.Collections.Generic; @@ -25,11 +26,13 @@ public SalesReceiptLine() public int? SalesInvoiceLineId { get; set; } public int? ItemId { get; set; } public int? AccountToCreditId { get; set; } + public virtual Item Item { get; set; } public int? MeasurementId { get; set; } public decimal? Quantity { get; set; } public decimal? Discount { get; set; } public decimal? Amount { get; set; } public decimal AmountPaid { get; set; } + public virtual Measurement Measurement { get; set; } public virtual SalesReceiptHeader SalesReceiptHeader { get; set; } public virtual SalesInvoiceLine SalesInvoiceLine { get; set; } public virtual Account AccountToCredit { get; set; } diff --git a/src/Core/Domain/TaxSystem/ItemTaxGroup.cs b/src/Core/Domain/TaxSystem/ItemTaxGroup.cs index 3899b6977..b81545890 100644 --- a/src/Core/Domain/TaxSystem/ItemTaxGroup.cs +++ b/src/Core/Domain/TaxSystem/ItemTaxGroup.cs @@ -7,6 +7,7 @@ //----------------------------------------------------------------------- using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; namespace Core.Domain.TaxSystem @@ -20,6 +21,8 @@ public ItemTaxGroup() } public string Name { get; set; } + + [Display(Name = "Fully Exempt")] public bool IsFullyExempt { get; set; } public virtual ICollection ItemTaxGroupTax { get; set; } diff --git a/src/Core/Domain/TaxSystem/TaxGroup.cs b/src/Core/Domain/TaxSystem/TaxGroup.cs index da67483db..9192e920d 100644 --- a/src/Core/Domain/TaxSystem/TaxGroup.cs +++ b/src/Core/Domain/TaxSystem/TaxGroup.cs @@ -7,6 +7,7 @@ //----------------------------------------------------------------------- using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; namespace Core.Domain.TaxSystem @@ -19,6 +20,8 @@ public TaxGroup() TaxGroupTax = new HashSet(); } public string Description { get; set; } + + [Display(Name = "Fully Exempt")] public bool TaxAppliedToShipping { get; set; } public bool IsActive { get; set; } public virtual ICollection TaxGroupTax { get; set; } diff --git a/src/Dto/Administration/AuditLog.cs b/src/Dto/Administration/AuditLog.cs index 383195774..0310beeda 100644 --- a/src/Dto/Administration/AuditLog.cs +++ b/src/Dto/Administration/AuditLog.cs @@ -4,13 +4,13 @@ namespace Dto.Administration { public class AuditLog : BaseDto { - public string UserName { get; set; } + public string? UserName { get; set; } public DateTime AuditEventDateUTC { get; set; } public int AuditEventType { get; set; } - public string TableName { get; set; } - public string RecordId { get; set; } - public string FieldName { get; set; } - public string OriginalValue { get; set; } - public string NewValue { get; set; } + public string? TableName { get; set; } + public string? RecordId { get; set; } + public string? FieldName { get; set; } + public string? OriginalValue { get; set; } + public string? NewValue { get; set; } } } diff --git a/src/Dto/Administration/Company.cs b/src/Dto/Administration/Company.cs index d5f63afbe..a4fb861fc 100644 --- a/src/Dto/Administration/Company.cs +++ b/src/Dto/Administration/Company.cs @@ -6,17 +6,21 @@ public class Company : BaseDto { [Required] [Display(Name = "Company Code")] - public string CompanyCode { get; set; } + public string? CompanyCode { get; set; } [Required] [Display(Name = "Name")] - public string Name { get; set; } + public string? Name { get; set; } [Required] [Display(Name = "Short Name")] - public string ShortName { get; set; } + public string? ShortName { get; set; } + + [Required] + [Display(Name = "CRA")] + public string? CRA { get; set; } [Display(Name = "Logo")] - public byte[] Logo { get; set; } + public byte[]? Logo { get; set; } } } diff --git a/src/Dto/BaseModel.cs b/src/Dto/BaseModel.cs index 7e1baf1fa..b5ae176dd 100644 --- a/src/Dto/BaseModel.cs +++ b/src/Dto/BaseModel.cs @@ -3,6 +3,6 @@ public abstract class BaseDto { public virtual int Id { get; set; } - public string ModifiedBy { get; set; } + public string? ModifiedBy { get; set; } } } diff --git a/src/Dto/Common/Contact.cs b/src/Dto/Common/Contact.cs index a659c19f2..73bf735de 100644 --- a/src/Dto/Common/Contact.cs +++ b/src/Dto/Common/Contact.cs @@ -8,14 +8,14 @@ public class Contact : BaseDto [Display(Name = "First Name")] [Required] [StringLength(100)] - public string FirstName { get; set; } + public string? FirstName { get; set; } [Display(Name = "Last Name")] [Required] [StringLength(100)] - public string LastName { get; set; } + public string? LastName { get; set; } public Party Party { get; set; } - public string MiddleName { get; set; } + public string? MiddleName { get; set; } public int CustomerId { get; set; } public int VendorId { get; set; } diff --git a/src/Dto/Common/Party.cs b/src/Dto/Common/Party.cs index 231be033b..3178b05fe 100644 --- a/src/Dto/Common/Party.cs +++ b/src/Dto/Common/Party.cs @@ -4,10 +4,10 @@ namespace Dto.Common { public class Party : BaseDto { - public string Name { get; set; } - public string Email { get; set; } - public string Website { get; set; } - public string Phone { get; set; } - public string Fax { get; set; } + public string? Name { get; set; } + public string? Email { get; set; } + public string? Website { get; set; } + public string? Phone { get; set; } + public string? Fax { get; set; } } } diff --git a/src/Dto/Common/Status.cs b/src/Dto/Common/Status.cs index 45c57debf..16be2f2b7 100644 --- a/src/Dto/Common/Status.cs +++ b/src/Dto/Common/Status.cs @@ -9,6 +9,6 @@ namespace Dto.Common public class Status { public int Id { get; set; } - public string Description { get; set; } + public string? Description { get; set; } } } diff --git a/src/Dto/Dto.csproj b/src/Dto/Dto.csproj index 5b795aa83..8c76d5cee 100644 --- a/src/Dto/Dto.csproj +++ b/src/Dto/Dto.csproj @@ -1,12 +1,8 @@  - - netstandard2.1 + net9.0 Library + enable + true - - - - - \ No newline at end of file diff --git a/src/Dto/Financial/Account.cs b/src/Dto/Financial/Account.cs index 7a21fc67e..075e6aef9 100644 --- a/src/Dto/Financial/Account.cs +++ b/src/Dto/Financial/Account.cs @@ -7,9 +7,9 @@ public class Account : BaseDto public int AccountClassId { get; set; } public int? ParentAccountId { get; set; } public int CompanyId { get; set; } - public string AccountCode { get; set; } - public string AccountName { get; set; } - public string Description { get; set; } + public string? AccountCode { get; set; } + public string? AccountName { get; set; } + public string? Description { get; set; } public bool IsCash { get; set; } public bool IsContraAccount { get; set; } public decimal Balance { get; set; } diff --git a/src/Dto/Financial/AccountClass.cs b/src/Dto/Financial/AccountClass.cs index ac276df1b..8a9511f86 100644 --- a/src/Dto/Financial/AccountClass.cs +++ b/src/Dto/Financial/AccountClass.cs @@ -2,7 +2,7 @@ { public class AccountClass : BaseDto { - public string Name { get; set; } - public string NormalBalance { get; set; } + public string? Name { get; set; } + public string? NormalBalance { get; set; } } } diff --git a/src/Dto/Financial/Bank.cs b/src/Dto/Financial/Bank.cs index 3ca3d8e2b..41de3af34 100644 --- a/src/Dto/Financial/Bank.cs +++ b/src/Dto/Financial/Bank.cs @@ -2,8 +2,8 @@ { public class Bank : BaseDto { - public string Name { get; set; } - public string AccountNo {get;set;} - public string BankName { get; set; } + public string? Name { get; set; } + public string? AccountNo {get;set;} + public string? BankName { get; set; } } } diff --git a/src/Dto/Financial/JournalEntry.cs b/src/Dto/Financial/JournalEntry.cs index 7d1b67561..620df0577 100644 --- a/src/Dto/Financial/JournalEntry.cs +++ b/src/Dto/Financial/JournalEntry.cs @@ -6,8 +6,8 @@ public class JournalEntry : BaseDto { public DateTime JournalDate { get; set; } public int? VoucherType { get; set; } - public string ReferenceNo { get; set; } - public string Memo { get; set; } + public string? ReferenceNo { get; set; } + public string? Memo { get; set; } public bool? Posted { get; set; } public bool? ReadyForPosting { get; set; } public decimal? debitAmount { get { return GetDebitAmount(); } } @@ -47,6 +47,6 @@ public class JournalEntryLine : BaseDto public int? AccountId { get; set; } public int DrCr { get; set; } public decimal? Amount { get; set; } - public string Memo { get; set; } + public string? Memo { get; set; } } } diff --git a/src/Dto/Financial/MasterGeneralLedger.cs b/src/Dto/Financial/MasterGeneralLedger.cs index 775018f0d..deff0dd33 100644 --- a/src/Dto/Financial/MasterGeneralLedger.cs +++ b/src/Dto/Financial/MasterGeneralLedger.cs @@ -11,10 +11,10 @@ public class MasterGeneralLedger : BaseDto public new int? Id { get; set; } public int AccountId { get; set; } public int CurrencyId { get; set; } - public string DocumentType { get; set; } + public string? DocumentType { get; set; } public int? TransactionNo { get; set; } - public string AccountCode { get; set; } - public string AccountName { get; set; } + public string? AccountCode { get; set; } + public string? AccountName { get; set; } public DateTime? Date { get; set; } public decimal? Debit { get; set; } public decimal? Credit { get; set; } diff --git a/src/Dto/Financial/TreeViewAccounts.cs b/src/Dto/Financial/TreeViewAccounts.cs index 279cc4d5a..fb734b123 100644 --- a/src/Dto/Financial/TreeViewAccounts.cs +++ b/src/Dto/Financial/TreeViewAccounts.cs @@ -4,11 +4,11 @@ namespace Dto.Financial { public class TreeViewAccounts { - public IList Groups { get; set; } + public IList? Groups { get; set; } } public class Group { - public string Name { get; set; } - public IList Groups { get; set; } + public string? Name { get; set; } + public IList? Groups { get; set; } } } diff --git a/src/Dto/Inventory/InventoryControlJournal.cs b/src/Dto/Inventory/InventoryControlJournal.cs index 304fd561c..ea19f1f46 100644 --- a/src/Dto/Inventory/InventoryControlJournal.cs +++ b/src/Dto/Inventory/InventoryControlJournal.cs @@ -6,8 +6,8 @@ public class InventoryControlJournal : BaseDto { public decimal? In { get; set; } public decimal? Out { get; set; } - public string Item { get; set; } - public string Measurement { get; set; } + public string? Item { get; set; } + public string? Measurement { get; set; } public DateTime Date { get; set; } } } diff --git a/src/Dto/Inventory/Item.cs b/src/Dto/Inventory/Item.cs index bdcc4a8be..7292705e3 100644 --- a/src/Dto/Inventory/Item.cs +++ b/src/Dto/Inventory/Item.cs @@ -4,13 +4,13 @@ namespace Dto.Inventory { public class Item : BaseDto { - public string No { get; set; } + public string? No { get; set; } [Required] - public string Code { get; set; } + public string? Code { get; set; } [Required] - public string Description { get; set; } - public string PurchaseDescription { get; set; } - public string SellDescription { get; set; } + public string? Description { get; set; } + public string? PurchaseDescription { get; set; } + public string? SellDescription { get; set; } public decimal? Cost { get; set; } public decimal? Price { get; set; } public decimal? QuantityOnHand { get; set; } @@ -25,7 +25,7 @@ public class Item : BaseDto public int? InventoryAccountId { get; set; } public int? CostOfGoodsSoldAccountId { get; set; } public int? InventoryAdjustmentAccountId { get; set; } - public string ItemTaxGroupName { get; set; } - public string Measurement { get; set; } + public string? ItemTaxGroupName { get; set; } + public string? Measurement { get; set; } } } diff --git a/src/Dto/Inventory/ItemCategory.cs b/src/Dto/Inventory/ItemCategory.cs index 878d6b908..fbc6cf3a4 100644 --- a/src/Dto/Inventory/ItemCategory.cs +++ b/src/Dto/Inventory/ItemCategory.cs @@ -2,6 +2,6 @@ { public class ItemCategory : BaseDto { - public string Name { get; set; } + public string? Name { get; set; } } } diff --git a/src/Dto/Inventory/Measurement.cs b/src/Dto/Inventory/Measurement.cs index 519b0f41f..0a43f4b7f 100644 --- a/src/Dto/Inventory/Measurement.cs +++ b/src/Dto/Inventory/Measurement.cs @@ -2,7 +2,7 @@ { public class Measurement:BaseDto { - public string Code { get; set; } - public string Description { get; set; } + public string? Code { get; set; } + public string? Description { get; set; } } } diff --git a/src/Dto/Purchasing/PurchaseInvoice.cs b/src/Dto/Purchasing/PurchaseInvoice.cs index f4ccb5b25..5c6d85666 100644 --- a/src/Dto/Purchasing/PurchaseInvoice.cs +++ b/src/Dto/Purchasing/PurchaseInvoice.cs @@ -4,19 +4,19 @@ namespace Dto.Purchasing { public class PurchaseInvoice : BaseDto { - public string No { get; set; } + public string? No { get; set; } public int? PurchaseOrderHeaderId { get; set; } - public string VendorInvoiceNo { get; set; } + public string? VendorInvoiceNo { get; set; } public int VendorId { get; set; } - public string VendorName { get; set; } + public string? VendorName { get; set; } public DateTime InvoiceDate { get; set; } public decimal Amount { get { return GetTotalAmount(); } } public decimal AmountPaid { get; set; } - public bool IsPaid { get; set; } + public bool IsPaid { get; set; } = false; public bool Posted { get; set; } public int? FromPurchaseOrderId { get; set; } public int? PaymentTermId { get; set; } - public string ReferenceNo { get; set; } + public string? ReferenceNo { get; set; } public bool? ReadyForPosting { get; set; } public System.Collections.Generic.IList PurchaseInvoiceLines { get; set; } @@ -35,7 +35,7 @@ private decimal GetTotalAmountLessTax() decimal total = 0; foreach (var line in PurchaseInvoiceLines) { - decimal quantityXamount = (line.Amount.Value * line.Quantity.Value); + decimal quantityXamount = (line.Amount!.Value * line.Quantity!.Value); decimal discount = 0; if (line.Discount.HasValue) discount = (line.Discount.Value / 100) > 0 ? (quantityXamount * (line.Discount.Value / 100)) : 0; diff --git a/src/Dto/Purchasing/PurchaseOrder.cs b/src/Dto/Purchasing/PurchaseOrder.cs index 714e82df4..2c32c9cca 100644 --- a/src/Dto/Purchasing/PurchaseOrder.cs +++ b/src/Dto/Purchasing/PurchaseOrder.cs @@ -4,15 +4,15 @@ namespace Dto.Purchasing { public class PurchaseOrder : BaseDto { - public string No { get; set; } + public string? No { get; set; } public int? PaymentTermId { get; set; } public int VendorId { get; set; } - public string VendorName { get; set; } + public string? VendorName { get; set; } public DateTime OrderDate { get; set; } public decimal Amount { get { return GetTotalAmount(); } } public bool Completed { get; set; } - public string ReferenceNo { get; set; } + public string? ReferenceNo { get; set; } public int StatusId { get; set; } public System.Collections.Generic.IList PurchaseOrderLines { get; set; } @@ -31,7 +31,7 @@ private decimal GetTotalAmountLessTax() decimal total = 0; foreach (var line in PurchaseOrderLines) { - decimal quantityXamount = (line.Amount.Value * line.Quantity.Value); + decimal quantityXamount = (line.Amount!.Value * line.Quantity!.Value); decimal discount = 0; if (line.Discount.HasValue) discount = (line.Discount.Value / 100) > 0 ? (quantityXamount * (line.Discount.Value / 100)) : 0; diff --git a/src/Dto/Purchasing/Vendor.cs b/src/Dto/Purchasing/Vendor.cs index 6c94f5761..5a3d3ea95 100644 --- a/src/Dto/Purchasing/Vendor.cs +++ b/src/Dto/Purchasing/Vendor.cs @@ -6,21 +6,21 @@ namespace Dto.Purchasing { public class Vendor : BaseDto { - public string No { get; set; } + public string? No { get; set; } [Required] - public string Name { get; set; } - public string Email { get; set; } - public string Website { get; set; } - public string Phone { get; set; } - public string Fax { get; set; } + public string? Name { get; set; } + public string? Email { get; set; } + public string? Website { get; set; } + public string? Phone { get; set; } + public string? Fax { get; set; } public int? AccountsPayableAccountId { get; set; } public int? PurchaseAccountId { get; set; } public int? PurchaseDiscountAccountId { get; set; } public int? PaymentTermId { get; set; } public int? TaxGroupId { get; set; } public decimal Balance { get; set; } - public string Contact { get; set; } - public string TaxGroup { get; set; } + public string? Contact { get; set; } + public string? TaxGroup { get; set; } public Contact PrimaryContact { get; set; } public Vendor() diff --git a/src/Dto/Sales/CreateCustomer.cs b/src/Dto/Sales/CreateCustomer.cs index 5d99fad9c..aaf4ef974 100644 --- a/src/Dto/Sales/CreateCustomer.cs +++ b/src/Dto/Sales/CreateCustomer.cs @@ -2,7 +2,7 @@ { public class CreateCustomer { - public string Name { get; set; } - public string Phone { get; set; } + public string? Name { get; set; } + public string? Phone { get; set; } } } diff --git a/src/Dto/Sales/Customer.cs b/src/Dto/Sales/Customer.cs index b4321b445..d070d5346 100644 --- a/src/Dto/Sales/Customer.cs +++ b/src/Dto/Sales/Customer.cs @@ -6,13 +6,13 @@ namespace Dto.Sales { public class Customer : BaseDto { - public string No { get; set; } + public string? No { get; set; } [Required] - public string Name { get; set; } - public string Email { get; set; } - public string Website { get; set; } - public string Phone { get; set; } - public string Fax { get; set; } + public string? Name { get; set; } + public string? Email { get; set; } + public string? Website { get; set; } + public string? Phone { get; set; } + public string? Fax { get; set; } public int? AccountsReceivableId { get; set; } public int? SalesAccountId { get; set; } @@ -21,10 +21,10 @@ public class Customer : BaseDto public int? TaxGroupId { get; set; } public int? PaymentTermId { get; set; } public decimal Balance { get; set; } - public string Contact { get; set; } - public string TaxGroup { get; set; } - public Contact PrimaryContact { get; set; } - public IEnumerable Invoices { get; set; } + public string? Contact { get; set; } + public string? TaxGroup { get; set; } + public Contact? PrimaryContact { get; set; } + public IEnumerable? Invoices { get; set; } public Customer() { PrimaryContact = new Contact(); diff --git a/src/Dto/Sales/MonthlySales.cs b/src/Dto/Sales/MonthlySales.cs index a25e746f4..64927459c 100644 --- a/src/Dto/Sales/MonthlySales.cs +++ b/src/Dto/Sales/MonthlySales.cs @@ -2,7 +2,7 @@ { public class MonthlySales { - public string Month { get; set; } + public string? Month { get; set; } public decimal Amount { get; set; } } diff --git a/src/Dto/Sales/SalesInvoice.cs b/src/Dto/Sales/SalesInvoice.cs index a49c836e0..f7a3b1898 100644 --- a/src/Dto/Sales/SalesInvoice.cs +++ b/src/Dto/Sales/SalesInvoice.cs @@ -1,32 +1,36 @@ using System; using System.Collections; using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; namespace Dto.Sales { public class SalesInvoice : BaseDto { - public string No { get; set; } - public int? CustomerId { get; set; } + public string? No { get; set; } + [Required(ErrorMessage = "Customer is required")] + public int CustomerId { get; set; } public DateTime InvoiceDate { get; set; } + [Required(ErrorMessage = "Payment Term is required")] public int? PaymentTermId { get; set; } public int? FromSalesOrderId { get; set; } public int? FromSalesDeliveryId { get; set; } - public string CustomerName { get; set; } - public string CustomerEmail { get; set; } + public string? CustomerName { get; set; } + public string? CustomerEmail { get; set; } public decimal Amount { get { return GetTotalAmount(); } } public decimal TotalAllocatedAmount { get; set; } - public string ReferenceNo { get; set; } + public string? ReferenceNo { get; set; } public bool Posted { get; set; } public bool? ReadyForPosting { get; set; } - public string CompanyName { get; set; } - public string CompanyEmail { get; set; } + public string? CompanyName { get; set; } + public string? CompanyEmail { get; set; } public decimal? TotalAmountAfterTax { get; set; } - public IList SalesInvoiceLines { get; set; } + public IList? SalesInvoiceLines { get; set; } public decimal? TotalTax { get; set; } public SalesInvoice() { SalesInvoiceLines = new List(); + InvoiceDate = DateTime.Now; } private decimal GetTotalAmount() @@ -37,9 +41,14 @@ private decimal GetTotalAmount() private decimal GetTotalAmountWithoutTax() { decimal total = 0; - foreach (var line in SalesInvoiceLines) + foreach (var line in SalesInvoiceLines!) { - decimal quantityXamount = (line.Amount.Value * line.Quantity.Value); + if(line.Amount is null || line.Quantity is null) + { + continue; + } + + decimal quantityXamount = (line.Amount!.Value * line.Quantity!.Value); decimal discount = 0; if (line.Discount.HasValue) discount = (line.Discount.Value / 100) > 0 ? (quantityXamount * (line.Discount.Value / 100)) : 0; @@ -51,13 +60,21 @@ private decimal GetTotalAmountWithoutTax() public class SalesInvoiceLine : BaseDto { + [Required(ErrorMessage = "Item is required")] public int? ItemId { get; set; } - public int? MeasurementId { get; set; } + [Required(ErrorMessage = "Quantity is required")] + [Range(0, 1000000, ErrorMessage = "Quantity must be between 0 and 1000000")] public decimal? Quantity { get; set; } - public decimal? Discount { get; set; } + [Required(ErrorMessage = "Amount is required")] + [Range(0, 1000000, ErrorMessage = "Amount must be between 0 and 1000000")] public decimal? Amount { get; set; } - public string MeasurementDescription { get; set; } - public string ItemNo { get; set; } - public string ItemDescription { get; set; } + [Required(ErrorMessage = "Discount is required")] + [Range(0, 100, ErrorMessage = "Discount must be between 0 and 100")] + public decimal? Discount { get; set; } + [Required(ErrorMessage = "Measurement is required")] + public int? MeasurementId { get; set; } + public string? MeasurementDescription { get; set; } + public string? ItemNo { get; set; } + public string? ItemDescription { get; set; } } -} +} \ No newline at end of file diff --git a/src/Dto/Sales/SalesOrder.cs b/src/Dto/Sales/SalesOrder.cs index df42de9b5..04402aa51 100644 --- a/src/Dto/Sales/SalesOrder.cs +++ b/src/Dto/Sales/SalesOrder.cs @@ -5,22 +5,22 @@ namespace Dto.Sales { public class SalesOrder : BaseDto { - public string No { get; set; } - public int? CustomerId { get; set; } + public string No { get; set; } = "1"; + public int CustomerId { get; set; } = 1; public DateTime OrderDate { get; set; } - public int? PaymentTermId { get; set; } - public string ReferenceNo { get; set; } + public int? PaymentTermId { get; set; } = 1; + public string ReferenceNo { get; set; } = "1"; public decimal? Amount { get { return GetTotalAmount(); } } - public string CustomerNo { get; set; } - public string CustomerName { get; set; } - public int StatusId { get; set; } - - public int? QuotationId { get; set; } + public string CustomerNo { get; set; } = "1"; + public string CustomerName { get; set; } = "1"; + public int StatusId { get; set; } = 1; + public int? QuotationId { get; set; } = 1; public IList SalesOrderLines { get; set; } public SalesOrder() { SalesOrderLines = new List(); + OrderDate = DateTime.Now; // TODO: Can be set by user } private decimal GetTotalAmount() @@ -33,7 +33,7 @@ private decimal GetTotalAmountLessTax() decimal total = 0; foreach (var line in SalesOrderLines) { - decimal quantityXamount = (line.Amount.Value * line.Quantity.Value); + decimal quantityXamount = (line.Amount!.Value * line.Quantity!.Value); decimal discount = 0; if (line.Discount.HasValue) discount = (line.Discount.Value / 100) > 0 ? (quantityXamount * (line.Discount.Value / 100)) : 0; @@ -50,9 +50,9 @@ public class SalesOrderLine : BaseDto public decimal? Quantity { get; set; } public decimal? Discount { get; set; } public decimal? Amount { get; set; } - public string MeasurementDescription { get; set; } - public string ItemNo { get; set; } - public string ItemDescription { get; set; } + public string? MeasurementDescription { get; set; } + public string? ItemNo { get; set; } + public string? ItemDescription { get; set; } public decimal? RemainingQtyToInvoice { get; set; } } } diff --git a/src/Dto/Sales/SalesQuotation.cs b/src/Dto/Sales/SalesQuotation.cs index e6fdd7470..01cb1f6af 100644 --- a/src/Dto/Sales/SalesQuotation.cs +++ b/src/Dto/Sales/SalesQuotation.cs @@ -5,22 +5,20 @@ namespace Dto.Sales { public class SalesQuotation : BaseDto { - public string No { get; set; } + public string? No { get; set; } public int? CustomerId { get; set; } - public string CustomerName { get; set; } + public string? CustomerName { get; set; } public DateTime QuotationDate { get; set; } public int? PaymentTermId { get; set; } - public string ReferenceNo { get; set; } + public string? ReferenceNo { get; set; } public decimal Amount { get { return GetTotalAmount(); } } public int StatusId { get; set; } - - public string SalesQuoteStatus { get; set; } - + public string? SalesQuoteStatus { get; set; } public virtual List SalesQuotationLines { get; set; } - public SalesQuotation() { SalesQuotationLines = new List(); + QuotationDate = DateTime.Now; } private decimal GetTotalAmount() @@ -33,7 +31,7 @@ private decimal GetTotalAmountLessTax() decimal total = 0; foreach (var line in SalesQuotationLines) { - decimal quantityXamount = (line.Amount.Value * line.Quantity.Value); + decimal quantityXamount = (line.Amount!.Value * line.Quantity!.Value); decimal discount = 0; if(line.Discount.HasValue) discount = (line.Discount.Value / 100) > 0 ? (quantityXamount * (line.Discount.Value / 100)) : 0; @@ -50,5 +48,7 @@ public class SalesQuotationLine : BaseDto public decimal? Quantity { get; set; } public decimal? Amount { get; set; } public decimal? Discount { get; set; } + public string? ItemDescription { get; set; } + public string? MeasurementDescription { get; set; } } } diff --git a/src/Dto/Sales/SalesReceipt.cs b/src/Dto/Sales/SalesReceipt.cs index 5e5c9cf85..349437c0b 100644 --- a/src/Dto/Sales/SalesReceipt.cs +++ b/src/Dto/Sales/SalesReceipt.cs @@ -4,22 +4,22 @@ namespace Dto.Sales { public class SalesReceipt : BaseDto { - public string ReceiptNo { get; set; } + public string? ReceiptNo { get; set; } public int CustomerId { get; set; } - public string CustomerName { get; set; } + public string? CustomerName { get; set; } public decimal Amount { get; set; } public decimal RemainingAmountToAllocate { get; set; } public int AccountToDebitId { get; set; } - public string AccountToDebit { get; set; } + public string? AccountToDebit { get; set; } public int GeneralLedgerHederId { get; set; } public DateTime ReceiptDate { get; set; } - public string ReferenceNo { get; set; } + public string? ReferenceNo { get; set; } } public class SalesReceiptLine : BaseDto { public int AccountToCreditId { get; set; } - public string AccountToCredit { get; set; } + public string? AccountToCredit { get; set; } public decimal Amount { get; set; } } } diff --git a/src/Dto/Security/Group.cs b/src/Dto/Security/Group.cs index b7869ccbc..bf00d857a 100644 --- a/src/Dto/Security/Group.cs +++ b/src/Dto/Security/Group.cs @@ -4,8 +4,8 @@ namespace Dto.Security { public class Group : BaseDto { - public string Name { get; set; } - public string DisplayName { get; set; } + public string? Name { get; set; } + public string? DisplayName { get; set; } public IList Permissions { get; set; } public Group() diff --git a/src/Dto/Security/Permission.cs b/src/Dto/Security/Permission.cs index 286707aab..a0e8f5dc7 100644 --- a/src/Dto/Security/Permission.cs +++ b/src/Dto/Security/Permission.cs @@ -2,8 +2,8 @@ { public class Permission : BaseDto { - public string Name { get; set; } - public string DisplayName { get; set; } - public Group Group { get; set; } + public string? Name { get; set; } + public string? DisplayName { get; set; } + public Group? Group { get; set; } } } diff --git a/src/Dto/Security/Role.cs b/src/Dto/Security/Role.cs index aaa9e0e6b..4f4df1f0b 100644 --- a/src/Dto/Security/Role.cs +++ b/src/Dto/Security/Role.cs @@ -4,8 +4,8 @@ namespace Dto.Security { public class Role : BaseDto { - public string Name { get; set; } - public string DisplayName { get; set; } + public string? Name { get; set; } + public string? DisplayName { get; set; } public bool SysAdmin { get; set; } public IList Users { get; set; } public IList Permissions { get; set; } diff --git a/src/Dto/Security/Token.cs b/src/Dto/Security/Token.cs new file mode 100644 index 000000000..ad2299338 --- /dev/null +++ b/src/Dto/Security/Token.cs @@ -0,0 +1,4 @@ +namespace Dto.Security +{ + public record Token(string AccessToken, string RefreshToken); +} diff --git a/src/Dto/Security/User.cs b/src/Dto/Security/User.cs index 651758585..098b9748a 100644 --- a/src/Dto/Security/User.cs +++ b/src/Dto/Security/User.cs @@ -4,10 +4,10 @@ namespace Dto.Security { public class User : BaseDto { - public string FirstName { get; set; } - public string LastName { get; set; } - public string UserName { get; set; } - public string Email { get; set; } + public string? FirstName { get; set; } + public string? LastName { get; set; } + public string? UserName { get; set; } + public string? Email { get; set; } public IList Roles { get; set; } public bool SysAdmin { get { return IsSystemAdministrators(); } } diff --git a/src/Dto/TaxSystem/ItemTaxGroup.cs b/src/Dto/TaxSystem/ItemTaxGroup.cs index 2d2227033..19ac0c171 100644 --- a/src/Dto/TaxSystem/ItemTaxGroup.cs +++ b/src/Dto/TaxSystem/ItemTaxGroup.cs @@ -1,10 +1,13 @@ using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; namespace Dto.TaxSystem { public class ItemTaxGroup : BaseDto { - public string Name { get; set; } + public string? Name { get; set; } + + [Display(Name = "Fully Exempt")] public bool IsFullyExempt { get; set; } public IList Taxes { get; set; } diff --git a/src/Dto/TaxSystem/Tax.cs b/src/Dto/TaxSystem/Tax.cs index 6a8d9bbe4..818ac732d 100644 --- a/src/Dto/TaxSystem/Tax.cs +++ b/src/Dto/TaxSystem/Tax.cs @@ -2,15 +2,15 @@ { public class Tax : BaseDto { - public string TaxName { get; set; } - public string TaxCode { get; set; } + public string? TaxName { get; set; } + public string? TaxCode { get; set; } public decimal Rate { get; set; } public bool IsActive { get; set; } } public class TaxSystemDto { - public System.Collections.Generic.IEnumerable Taxes { get; set; } - public System.Collections.Generic.IEnumerable TaxGroups { get; set; } - public System.Collections.Generic.IEnumerable ItemTaxGroups { get; set; } + public System.Collections.Generic.IEnumerable? Taxes { get; set; } + public System.Collections.Generic.IEnumerable? TaxGroups { get; set; } + public System.Collections.Generic.IEnumerable? ItemTaxGroups { get; set; } } } diff --git a/src/Dto/TaxSystem/TaxForCreation.cs b/src/Dto/TaxSystem/TaxForCreation.cs new file mode 100644 index 000000000..f5f82c776 --- /dev/null +++ b/src/Dto/TaxSystem/TaxForCreation.cs @@ -0,0 +1,26 @@ +using System.ComponentModel.DataAnnotations; + +namespace Dto.TaxSystem +{ + public class TaxForCreation + { + public int SalesAccountId { get; set; } + public int PurchaseAccountId { get; set; } + + [Required(ErrorMessage = "The Tax Name is a required field.")] + [MaxLength(50, ErrorMessage = "Tax Name must be less than 20 characters.")] + public string? TaxName { get; set; } + + [Required(ErrorMessage = "The Tax Code is a required field.")] + [MaxLength(16, ErrorMessage = "Tax Code must be less than 20 characters.")] + public string? TaxCode { get; set; } + + [Range(0, 100, ErrorMessage = "Rate must be between 0 and 100.")] + public decimal Rate { get; set; } + + public bool IsActive { get; set; } + + public TaxGroup? TaxGroup { get; set; } + public ItemTaxGroup? ItemTaxGroup { get; set; } + } +} diff --git a/src/Dto/TaxSystem/TaxForUpdate.cs b/src/Dto/TaxSystem/TaxForUpdate.cs new file mode 100644 index 000000000..6196dad42 --- /dev/null +++ b/src/Dto/TaxSystem/TaxForUpdate.cs @@ -0,0 +1,16 @@ +using System.ComponentModel.DataAnnotations; + +namespace Dto.TaxSystem +{ + public class TaxForUpdate + { + public int SalesAccountId { get; set; } + public int PurchaseAccountId { get; set; } + + public Tax? Tax { get; set; } + + + public TaxGroup? TaxGroup { get; set; } + public ItemTaxGroup? ItemTaxGroup { get; set; } + } +} diff --git a/src/Dto/TaxSystem/TaxGroup.cs b/src/Dto/TaxSystem/TaxGroup.cs index 747391cfc..b2c72f603 100644 --- a/src/Dto/TaxSystem/TaxGroup.cs +++ b/src/Dto/TaxSystem/TaxGroup.cs @@ -1,10 +1,13 @@ using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; namespace Dto.TaxSystem { public class TaxGroup : BaseDto { - public string Description { get; set; } + public string? Description { get; set; } + + [Display (Name="Apply to shipping")] public bool TaxAppliedToShipping { get; set; } public bool IsActive { get; set; } public IList Taxes { get; set; } diff --git a/src/GoodBooksReact/.babelec.json b/src/GoodBooksReact/.babelec.json new file mode 100644 index 000000000..99ffbfd27 --- /dev/null +++ b/src/GoodBooksReact/.babelec.json @@ -0,0 +1,19 @@ +{ + "presets": [ + "@babel/preset-env", + "@babel/preset-react", + "@babel/preset-env", + "@babel/preset-react" + ], + "plugins": [ + "@babel/plugin-transform-runtime", + "@babel/plugin-transform-object-assign", + [ + "@babel/plugin-proposal-decorators", + { + "legacy": true + } + ], + ["@babel/plugin-proposal-class-properties", { "loose": true }] + ] + } \ No newline at end of file diff --git a/src/GoodBooksReact/.eslintrc.cjs b/src/GoodBooksReact/.eslintrc.cjs new file mode 100644 index 000000000..89a6c8f68 --- /dev/null +++ b/src/GoodBooksReact/.eslintrc.cjs @@ -0,0 +1,19 @@ +module.exports = { + root: true, + env: { browser: true, es2020: true }, + extends: [ + 'eslint:recommended', + 'plugin:@typescript-eslint/recommended', + 'plugin:react-hooks/recommended', + ], + ignorePatterns: ['dist', '.eslintrc.cjs'], + parser: '@typescript-eslint/parser', + plugins: ['react-refresh'], + rules: { + 'react-refresh/only-export-components': [ + 'warn', + { allowConstantExport: true }, + ], + "@typescript-eslint/no-explicit-any": "error" + } +} diff --git a/src/GoodBooksReact/.gitignore b/src/GoodBooksReact/.gitignore new file mode 100644 index 000000000..a547bf36d --- /dev/null +++ b/src/GoodBooksReact/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/src/GoodBooksReact/README.md b/src/GoodBooksReact/README.md new file mode 100644 index 000000000..0d6babedd --- /dev/null +++ b/src/GoodBooksReact/README.md @@ -0,0 +1,30 @@ +# React + TypeScript + Vite + +This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. + +Currently, two official plugins are available: + +- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh +- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh + +## Expanding the ESLint configuration + +If you are developing a production application, we recommend updating the configuration to enable type aware lint rules: + +- Configure the top-level `parserOptions` property like this: + +```js +export default { + // other rules... + parserOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + project: ['./tsconfig.json', './tsconfig.node.json'], + tsconfigRootDir: __dirname, + }, +} +``` + +- Replace `plugin:@typescript-eslint/recommended` to `plugin:@typescript-eslint/recommended-type-checked` or `plugin:@typescript-eslint/strict-type-checked` +- Optionally add `plugin:@typescript-eslint/stylistic-type-checked` +- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and add `plugin:react/recommended` & `plugin:react/jsx-runtime` to the `extends` list diff --git a/src/GoodBooksReact/errors.txt b/src/GoodBooksReact/errors.txt new file mode 100644 index 000000000..62c4291eb --- /dev/null +++ b/src/GoodBooksReact/errors.txt @@ -0,0 +1,472 @@ + +> goodbooksreact@0.0.0 tsc +> tsc + +src/components/Shared/Components/SelectPaymentTerm.tsx(6,25): error TS7006: Parameter 'e' implicitly has an 'any' type. +src/components/Shared/Components/SelectQuotationStatus.tsx(6,25): error TS7006: Parameter 'e' implicitly has an 'any' type. +src/components/Shared/Components/SelectVendor.tsx(6,20): error TS7006: Parameter 'e' implicitly has an 'any' type. +src/components/Shared/Components/SelectVendor.tsx(24,47): error TS2339: Property 'id' does not exist on type 'AsyncDisposable'. +src/components/Shared/Components/SelectVendor.tsx(24,67): error TS2339: Property 'id' does not exist on type 'AsyncDisposable'. +src/components/Shared/Components/SelectVendor.tsx(24,82): error TS2339: Property 'name' does not exist on type 'AsyncDisposable'. +src/components/Shared/Components/SelectVoucherType.tsx(6,25): error TS7006: Parameter 'e' implicitly has an 'any' type. +src/components/Shared/Stores/AppState.tsx(1,1): error TS6133: 'observable' is declared but its value is never read. +src/components/Shared/Stores/Common/CommonStore.tsx(1,21): error TS6133: 'extendObservable' is declared but its value is never read. +src/components/Shared/Stores/Common/CommonStore.tsx(1,39): error TS6133: 'action' is declared but its value is never read. +src/components/Shared/Stores/Common/CommonStore.tsx(31,36): error TS2345: Argument of type 'any' is not assignable to parameter of type 'never'. +src/components/Shared/Stores/Common/CommonStore.tsx(42,39): error TS2345: Argument of type 'any' is not assignable to parameter of type 'never'. +src/components/Shared/Stores/Common/CommonStore.tsx(50,29): error TS7006: Parameter 'result' implicitly has an 'any' type. +src/components/Shared/Stores/Common/CommonStore.tsx(53,34): error TS2345: Argument of type 'any' is not assignable to parameter of type 'never'. +src/components/Shared/Stores/Common/CommonStore.tsx(64,32): error TS2345: Argument of type 'any' is not assignable to parameter of type 'never'. +src/components/Shared/Stores/Common/CommonStore.tsx(75,39): error TS2345: Argument of type 'any' is not assignable to parameter of type 'never'. +src/components/Shared/Stores/Common/CommonStore.tsx(90,42): error TS2345: Argument of type 'any' is not assignable to parameter of type 'never'. +src/components/Shared/Stores/Common/CommonStore.tsx(101,35): error TS2345: Argument of type 'any' is not assignable to parameter of type 'never'. +src/components/Shared/Stores/Common/CommonStore.tsx(116,29): error TS7006: Parameter 'tax' implicitly has an 'any' type. +src/components/Shared/Stores/Common/CommonStore.tsx(125,29): error TS7006: Parameter 'tax' implicitly has an 'any' type. +src/components/Shared/Stores/Financials/JournalEntry.tsx(5,5): error TS2564: Property 'voucherType' has no initializer and is not definitely assigned in the constructor. +src/components/Shared/Stores/Financials/JournalEntry.tsx(6,5): error TS2564: Property 'journalDate' has no initializer and is not definitely assigned in the constructor. +src/components/Shared/Stores/Financials/JournalEntry.tsx(7,5): error TS2564: Property 'referenceNo' has no initializer and is not definitely assigned in the constructor. +src/components/Shared/Stores/Financials/JournalEntry.tsx(8,5): error TS2564: Property 'memo' has no initializer and is not definitely assigned in the constructor. +src/components/Shared/Stores/Financials/JournalEntryLine.tsx(8,17): error TS7006: Parameter 'id' implicitly has an 'any' type. +src/components/Shared/Stores/Financials/JournalEntryLine.tsx(8,21): error TS7006: Parameter 'accountId' implicitly has an 'any' type. +src/components/Shared/Stores/Financials/JournalEntryLine.tsx(8,32): error TS7006: Parameter 'drcr' implicitly has an 'any' type. +src/components/Shared/Stores/Financials/JournalEntryLine.tsx(8,38): error TS7006: Parameter 'amount' implicitly has an 'any' type. +src/components/Shared/Stores/Financials/JournalEntryLine.tsx(8,46): error TS7006: Parameter 'memo' implicitly has an 'any' type. +src/components/Shared/Stores/Financials/JournalEntryStore.tsx(1,39): error TS6133: 'action' is declared but its value is never read. +src/components/Shared/Stores/Financials/JournalEntryStore.tsx(1,47): error TS6133: 'intercept' is declared but its value is never read. +src/components/Shared/Stores/Financials/JournalEntryStore.tsx(1,58): error TS6133: 'reaction' is declared but its value is never read. +src/components/Shared/Stores/Financials/JournalEntryStore.tsx(3,1): error TS6133: 'd3' is declared but its value is never read. +src/components/Shared/Stores/Financials/JournalEntryStore.tsx(3,21): error TS7016: Could not find a declaration file for module 'd3'. 'D:/_playground/react/GoodBooksReact/node_modules/d3/src/index.js' implicitly has an 'any' type. + Try `npm i --save-dev @types/d3` if it exists or add a new declaration (.d.ts) file containing `declare module 'd3';` +src/components/Shared/Stores/Financials/JournalEntryStore.tsx(17,5): error TS7008: Member 'originalJournalEntry' implicitly has an 'any' type. +src/components/Shared/Stores/Financials/JournalEntryStore.tsx(20,17): error TS7008: Member 'validationErrors' implicitly has an 'any' type. +src/components/Shared/Stores/Financials/JournalEntryStore.tsx(45,19): error TS7006: Parameter 'dirty' implicitly has an 'any' type. +src/components/Shared/Stores/Financials/JournalEntryStore.tsx(49,23): error TS7006: Parameter 'initialized' implicitly has an 'any' type. +src/components/Shared/Stores/Financials/JournalEntryStore.tsx(55,29): error TS7006: Parameter 'result' implicitly has an 'any' type. +src/components/Shared/Stores/Financials/JournalEntryStore.tsx(58,21): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Financials/JournalEntryStore.tsx(60,17): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Financials/JournalEntryStore.tsx(61,17): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Financials/JournalEntryStore.tsx(62,17): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Financials/JournalEntryStore.tsx(63,17): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Financials/JournalEntryStore.tsx(64,17): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Financials/JournalEntryStore.tsx(65,17): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Financials/JournalEntryStore.tsx(66,17): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Financials/JournalEntryStore.tsx(68,29): error TS2531: Object is possibly 'null'. +src/components/Shared/Stores/Financials/JournalEntryStore.tsx(83,33): error TS6133: 'response' is declared but its value is never read. +src/components/Shared/Stores/Financials/JournalEntryStore.tsx(86,34): error TS7006: Parameter 'error' implicitly has an 'any' type. +src/components/Shared/Stores/Financials/JournalEntryStore.tsx(87,46): error TS7006: Parameter 'err' implicitly has an 'any' type. +src/components/Shared/Stores/Financials/JournalEntryStore.tsx(88,25): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Financials/JournalEntryStore.tsx(89,28): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Financials/JournalEntryStore.tsx(130,33): error TS6133: 'response' is declared but its value is never read. +src/components/Shared/Stores/Financials/JournalEntryStore.tsx(133,34): error TS7006: Parameter 'error' implicitly has an 'any' type. +src/components/Shared/Stores/Financials/JournalEntryStore.tsx(134,46): error TS7006: Parameter 'err' implicitly has an 'any' type. +src/components/Shared/Stores/Financials/JournalEntryStore.tsx(135,25): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Financials/JournalEntryStore.tsx(136,28): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Financials/JournalEntryStore.tsx(141,17): error TS7006: Parameter 'id' implicitly has an 'any' type. +src/components/Shared/Stores/Financials/JournalEntryStore.tsx(141,21): error TS7006: Parameter 'accountId' implicitly has an 'any' type. +src/components/Shared/Stores/Financials/JournalEntryStore.tsx(141,32): error TS7006: Parameter 'drcr' implicitly has an 'any' type. +src/components/Shared/Stores/Financials/JournalEntryStore.tsx(141,38): error TS7006: Parameter 'amount' implicitly has an 'any' type. +src/components/Shared/Stores/Financials/JournalEntryStore.tsx(141,46): error TS7006: Parameter 'memo' implicitly has an 'any' type. +src/components/Shared/Stores/Financials/JournalEntryStore.tsx(146,20): error TS7006: Parameter 'row' implicitly has an 'any' type. +src/components/Shared/Stores/Financials/JournalEntryStore.tsx(146,25): error TS7006: Parameter 'targetProperty' implicitly has an 'any' type. +src/components/Shared/Stores/Financials/JournalEntryStore.tsx(146,41): error TS7006: Parameter 'value' implicitly has an 'any' type. +src/components/Shared/Stores/Financials/JournalEntryStore.tsx(148,13): error TS7053: Element implicitly has an 'any' type because expression of type 'any' can't be used to index type 'JournalEntryLine'. +src/components/Shared/Stores/Financials/JournalEntryStore.tsx(151,20): error TS7006: Parameter 'row' implicitly has an 'any' type. +src/components/Shared/Stores/Financials/JournalEntryStore.tsx(155,24): error TS7006: Parameter 'date' implicitly has an 'any' type. +src/components/Shared/Stores/Financials/JournalEntryStore.tsx(159,24): error TS7006: Parameter 'refNo' implicitly has an 'any' type. +src/components/Shared/Stores/Financials/JournalEntryStore.tsx(163,17): error TS7006: Parameter 'memo' implicitly has an 'any' type. +src/components/Shared/Stores/Financials/JournalEntryStore.tsx(167,24): error TS7006: Parameter 'type' implicitly has an 'any' type. +src/components/Shared/Stores/Financials/JournalEntryStore.tsx(171,21): error TS7006: Parameter 'editMode' implicitly has an 'any' type. +src/components/Shared/Stores/Financials/JournalEntryUIStore.tsx(1,1): error TS6192: All imports in import declaration are unused. +src/components/Shared/Stores/Financials/JournalEntryUIStore.tsx(2,1): error TS6133: 'mobx' is declared but its value is never read. +src/components/Shared/Stores/Purchasing/PurchaseInvoice.tsx(5,5): error TS2564: Property 'fromPurchaseOrderId' has no initializer and is not definitely assigned in the constructor. +src/components/Shared/Stores/Purchasing/PurchaseInvoice.tsx(6,5): error TS2564: Property 'vendorId' has no initializer and is not definitely assigned in the constructor. +src/components/Shared/Stores/Purchasing/PurchaseInvoice.tsx(7,5): error TS2564: Property 'invoiceDate' has no initializer and is not definitely assigned in the constructor. +src/components/Shared/Stores/Purchasing/PurchaseInvoice.tsx(8,5): error TS2564: Property 'paymentTermId' has no initializer and is not definitely assigned in the constructor. +src/components/Shared/Stores/Purchasing/PurchaseInvoice.tsx(9,5): error TS2564: Property 'referenceNo' has no initializer and is not definitely assigned in the constructor. +src/components/Shared/Stores/Purchasing/PurchaseInvoice.tsx(13,5): error TS2564: Property 'statusId' has no initializer and is not definitely assigned in the constructor. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceLine.tsx(10,17): error TS7006: Parameter 'id' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceLine.tsx(10,21): error TS7006: Parameter 'itemId' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceLine.tsx(10,29): error TS7006: Parameter 'measurementId' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceLine.tsx(10,44): error TS7006: Parameter 'quantity' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceLine.tsx(10,54): error TS7006: Parameter 'amount' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceLine.tsx(10,62): error TS7006: Parameter 'discount' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(1,39): error TS6133: 'action' is declared but its value is never read. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(1,56): error TS6133: 'computed' is declared but its value is never read. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(18,17): error TS7008: Member 'validationErrors' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(20,17): error TS7008: Member 'purchaseInvoiceStatus' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(39,33): error TS7006: Parameter 'result' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(44,25): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(55,21): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(56,21): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(57,21): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(58,21): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(59,21): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(60,21): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(61,21): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(63,34): error TS6133: 'error' is declared but its value is never read. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(63,34): error TS7006: Parameter 'error' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(68,33): error TS7006: Parameter 'result' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(71,25): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(79,25): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(79,56): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(82,21): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(83,21): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(84,21): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(85,21): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(86,21): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(87,21): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(88,21): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(89,21): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(92,21): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(94,33): error TS2531: Object is possibly 'null'. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(99,34): error TS6133: 'error' is declared but its value is never read. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(99,34): error TS7006: Parameter 'error' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(115,13): error TS6133: 'gtotal' is declared but its value is never read. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(121,33): error TS7006: Parameter 'result' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(123,43): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(125,21): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(126,21): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(140,33): error TS6133: 'response' is declared but its value is never read. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(143,34): error TS7006: Parameter 'error' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(144,46): error TS7006: Parameter 'err' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(145,25): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(146,28): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(159,33): error TS6133: 'response' is declared but its value is never read. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(162,34): error TS7006: Parameter 'error' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(163,46): error TS7006: Parameter 'err' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(164,25): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(165,28): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(224,58): error TS6133: 'discount' is declared but its value is never read. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(242,58): error TS6133: 'discount' is declared but its value is never read. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(264,24): error TS7006: Parameter 'refNo' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(267,19): error TS7006: Parameter 'vendorId' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(271,24): error TS7006: Parameter 'paymentTermId' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(274,24): error TS7006: Parameter 'date' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(278,17): error TS7006: Parameter 'id' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(278,21): error TS7006: Parameter 'itemId' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(278,29): error TS7006: Parameter 'measurementId' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(278,44): error TS7006: Parameter 'quantity' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(278,54): error TS7006: Parameter 'amount' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(278,62): error TS7006: Parameter 'discount' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(283,20): error TS7006: Parameter 'row' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(287,20): error TS7006: Parameter 'row' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(287,25): error TS7006: Parameter 'targetProperty' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(287,41): error TS7006: Parameter 'value' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(289,13): error TS7053: Element implicitly has an 'any' type because expression of type 'any' can't be used to index type 'PurchaseInvoiceLine'. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(294,18): error TS7006: Parameter 'row' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(301,21): error TS7006: Parameter 'editMode' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(305,30): error TS7006: Parameter 'statusId' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(316,20): error TS7006: Parameter 'itemId' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(319,43): error TS2339: Property 'id' does not exist on type 'never'. +src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx(320,50): error TS2339: Property 'code' does not exist on type 'never'. +src/components/Shared/Stores/Purchasing/PurchaseOrder.tsx(4,5): error TS2564: Property 'id' has no initializer and is not definitely assigned in the constructor. +src/components/Shared/Stores/Purchasing/PurchaseOrder.tsx(5,5): error TS2564: Property 'vendorId' has no initializer and is not definitely assigned in the constructor. +src/components/Shared/Stores/Purchasing/PurchaseOrder.tsx(6,5): error TS2564: Property 'orderDate' has no initializer and is not definitely assigned in the constructor. +src/components/Shared/Stores/Purchasing/PurchaseOrder.tsx(7,5): error TS2564: Property 'paymentTermId' has no initializer and is not definitely assigned in the constructor. +src/components/Shared/Stores/Purchasing/PurchaseOrder.tsx(8,5): error TS2564: Property 'referenceNo' has no initializer and is not definitely assigned in the constructor. +src/components/Shared/Stores/Purchasing/PurchaseOrder.tsx(9,5): error TS2564: Property 'statusId' has no initializer and is not definitely assigned in the constructor. +src/components/Shared/Stores/Purchasing/PurchaseOrderLine.tsx(10,17): error TS7006: Parameter 'id' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseOrderLine.tsx(10,21): error TS7006: Parameter 'itemId' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseOrderLine.tsx(10,29): error TS7006: Parameter 'measurementId' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseOrderLine.tsx(10,44): error TS7006: Parameter 'quantity' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseOrderLine.tsx(10,54): error TS7006: Parameter 'amount' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseOrderLine.tsx(10,62): error TS7006: Parameter 'discount' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseOrderLine.tsx(10,72): error TS7006: Parameter 'code' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx(1,39): error TS6133: 'action' is declared but its value is never read. +src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx(1,56): error TS6133: 'computed' is declared but its value is never read. +src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx(18,17): error TS7008: Member 'validationErrors' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx(20,17): error TS7008: Member 'purchaseOrderStatus' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx(38,33): error TS7006: Parameter 'result' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx(39,21): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx(40,21): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx(41,21): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx(42,21): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx(43,21): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx(44,21): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx(45,21): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx(47,25): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx(55,25): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx(55,56): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx(57,21): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx(58,33): error TS2531: Object is possibly 'null'. +src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx(63,34): error TS6133: 'error' is declared but its value is never read. +src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx(63,34): error TS7006: Parameter 'error' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx(78,13): error TS6133: 'gtotal' is declared but its value is never read. +src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx(84,33): error TS7006: Parameter 'result' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx(86,43): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx(88,21): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx(89,21): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx(98,13): error TS2322: Type 'string' is not assignable to type 'Date'. +src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx(107,33): error TS6133: 'response' is declared but its value is never read. +src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx(110,34): error TS7006: Parameter 'error' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx(111,46): error TS7006: Parameter 'err' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx(112,25): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx(113,28): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx(120,58): error TS2367: This comparison appears to be unintentional because the types 'number' and 'string' have no overlap. +src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx(122,63): error TS2367: This comparison appears to be unintentional because the types 'number' and 'string' have no overlap. +src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx(124,59): error TS2367: This comparison appears to be unintentional because the types 'Date' and 'string' have no overlap. +src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx(172,58): error TS6133: 'discount' is declared but its value is never read. +src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx(190,58): error TS6133: 'discount' is declared but its value is never read. +src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx(211,24): error TS7006: Parameter 'refNo' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx(214,19): error TS7006: Parameter 'vendorId' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx(218,24): error TS7006: Parameter 'paymentTermId' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx(222,22): error TS7006: Parameter 'date' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx(226,17): error TS7006: Parameter 'id' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx(226,21): error TS7006: Parameter 'itemId' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx(226,29): error TS7006: Parameter 'measurementId' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx(226,44): error TS7006: Parameter 'quantity' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx(226,54): error TS7006: Parameter 'amount' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx(226,62): error TS7006: Parameter 'discount' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx(226,72): error TS7006: Parameter 'code' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx(231,20): error TS7006: Parameter 'row' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx(235,20): error TS7006: Parameter 'row' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx(235,25): error TS7006: Parameter 'targetProperty' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx(235,41): error TS7006: Parameter 'value' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx(237,13): error TS7053: Element implicitly has an 'any' type because expression of type 'any' can't be used to index type 'PurchaseOrderLine'. +src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx(242,18): error TS7006: Parameter 'row' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx(249,21): error TS7006: Parameter 'editMode' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx(253,28): error TS7006: Parameter 'statusId' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx(270,20): error TS7006: Parameter 'itemId' implicitly has an 'any' type. +src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx(273,43): error TS2339: Property 'id' does not exist on type 'never'. +src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx(274,50): error TS2339: Property 'code' does not exist on type 'never'. +src/components/Shared/Stores/Quotations/SalesQuotation.tsx(4,5): error TS2564: Property 'id' has no initializer and is not definitely assigned in the constructor. +src/components/Shared/Stores/Quotations/SalesQuotation.tsx(5,5): error TS2564: Property 'customerId' has no initializer and is not definitely assigned in the constructor. +src/components/Shared/Stores/Quotations/SalesQuotation.tsx(6,5): error TS2564: Property 'quotationDate' has no initializer and is not definitely assigned in the constructor. +src/components/Shared/Stores/Quotations/SalesQuotation.tsx(7,5): error TS2564: Property 'paymentTermId' has no initializer and is not definitely assigned in the constructor. +src/components/Shared/Stores/Quotations/SalesQuotation.tsx(8,5): error TS2564: Property 'referenceNo' has no initializer and is not definitely assigned in the constructor. +src/components/Shared/Stores/Quotations/SalesQuotation.tsx(9,5): error TS2564: Property 'statusId' has no initializer and is not definitely assigned in the constructor. +src/components/Shared/Stores/Quotations/SalesQuotationLine.tsx(10,17): error TS7006: Parameter 'id' implicitly has an 'any' type. +src/components/Shared/Stores/Quotations/SalesQuotationLine.tsx(10,21): error TS7006: Parameter 'itemId' implicitly has an 'any' type. +src/components/Shared/Stores/Quotations/SalesQuotationLine.tsx(10,29): error TS7006: Parameter 'measurementId' implicitly has an 'any' type. +src/components/Shared/Stores/Quotations/SalesQuotationLine.tsx(10,44): error TS7006: Parameter 'quantity' implicitly has an 'any' type. +src/components/Shared/Stores/Quotations/SalesQuotationLine.tsx(10,54): error TS7006: Parameter 'amount' implicitly has an 'any' type. +src/components/Shared/Stores/Quotations/SalesQuotationLine.tsx(10,62): error TS7006: Parameter 'discount' implicitly has an 'any' type. +src/components/Shared/Stores/Quotations/SalesQuotationLine.tsx(10,72): error TS7006: Parameter 'code' implicitly has an 'any' type. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(1,39): error TS6133: 'action' is declared but its value is never read. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(1,56): error TS6133: 'computed' is declared but its value is never read. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(3,1): error TS6133: 'd3' is declared but its value is never read. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(3,21): error TS7016: Could not find a declaration file for module 'd3'. 'D:/_playground/react/GoodBooksReact/node_modules/d3/src/index.js' implicitly has an 'any' type. + Try `npm i --save-dev @types/d3` if it exists or add a new declaration (.d.ts) file containing `declare module 'd3';` +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(19,17): error TS7008: Member 'salesQuotationStatus' implicitly has an 'any' type. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(20,17): error TS7008: Member 'validationErrors' implicitly has an 'any' type. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(23,17): error TS7006: Parameter 'quotationId' implicitly has an 'any' type. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(41,35): error TS7006: Parameter 'result' implicitly has an 'any' type. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(42,17): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(43,17): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(44,17): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(45,17): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(46,17): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(47,17): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(48,17): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(50,21): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(59,21): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(59,52): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(61,17): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(62,29): error TS2531: Object is possibly 'null'. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(84,13): error TS6133: 'gtotal' is declared but its value is never read. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(90,33): error TS7006: Parameter 'result' implicitly has an 'any' type. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(92,43): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(94,21): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(95,21): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(104,13): error TS2322: Type 'string' is not assignable to type 'Date'. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(116,37): error TS6133: 'response' is declared but its value is never read. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(119,38): error TS7006: Parameter 'error' implicitly has an 'any' type. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(120,50): error TS7006: Parameter 'err' implicitly has an 'any' type. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(121,29): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(122,32): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(132,82): error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(140,37): error TS6133: 'response' is declared but its value is never read. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(143,38): error TS7006: Parameter 'error' implicitly has an 'any' type. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(144,50): error TS7006: Parameter 'err' implicitly has an 'any' type. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(145,29): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(146,32): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(164,88): error TS2367: This comparison appears to be unintentional because the types 'number' and 'string' have no overlap. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(166,95): error TS2367: This comparison appears to be unintentional because the types 'number' and 'string' have no overlap. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(168,90): error TS2367: This comparison appears to be unintentional because the types 'number' and 'string' have no overlap. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(170,88): error TS2367: This comparison appears to be unintentional because the types 'number' and 'string' have no overlap. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(182,24): error TS7006: Parameter 'statusId' implicitly has an 'any' type. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(221,58): error TS6133: 'discount' is declared but its value is never read. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(239,58): error TS6133: 'discount' is declared but its value is never read. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(260,21): error TS7006: Parameter 'custId' implicitly has an 'any' type. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(264,24): error TS7006: Parameter 'termId' implicitly has an 'any' type. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(268,26): error TS7006: Parameter 'date' implicitly has an 'any' type. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(271,24): error TS7006: Parameter 'refNo' implicitly has an 'any' type. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(275,24): error TS7006: Parameter 'statusId' implicitly has an 'any' type. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(279,20): error TS7006: Parameter 'itemId' implicitly has an 'any' type. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(282,43): error TS2339: Property 'id' does not exist on type 'never'. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(283,50): error TS2339: Property 'code' does not exist on type 'never'. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(288,17): error TS7006: Parameter 'id' implicitly has an 'any' type. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(288,21): error TS7006: Parameter 'itemId' implicitly has an 'any' type. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(288,29): error TS7006: Parameter 'measurementId' implicitly has an 'any' type. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(288,44): error TS7006: Parameter 'quantity' implicitly has an 'any' type. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(288,54): error TS7006: Parameter 'amount' implicitly has an 'any' type. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(288,62): error TS7006: Parameter 'discount' implicitly has an 'any' type. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(288,72): error TS7006: Parameter 'code' implicitly has an 'any' type. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(293,20): error TS7006: Parameter 'row' implicitly has an 'any' type. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(297,20): error TS7006: Parameter 'row' implicitly has an 'any' type. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(297,25): error TS7006: Parameter 'targetProperty' implicitly has an 'any' type. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(297,41): error TS7006: Parameter 'value' implicitly has an 'any' type. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(299,9): error TS7053: Element implicitly has an 'any' type because expression of type 'any' can't be used to index type 'SalesQuotationLine'. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(303,18): error TS7006: Parameter 'row' implicitly has an 'any' type. +src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx(310,21): error TS7006: Parameter 'editMode' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesInvoice.tsx(6,5): error TS2564: Property 'customerId' has no initializer and is not definitely assigned in the constructor. +src/components/Shared/Stores/Sales/SalesInvoice.tsx(7,5): error TS2564: Property 'invoiceDate' has no initializer and is not definitely assigned in the constructor. +src/components/Shared/Stores/Sales/SalesInvoice.tsx(8,5): error TS2564: Property 'paymentTermId' has no initializer and is not definitely assigned in the constructor. +src/components/Shared/Stores/Sales/SalesInvoice.tsx(9,5): error TS2564: Property 'referenceNo' has no initializer and is not definitely assigned in the constructor. +src/components/Shared/Stores/Sales/SalesInvoiceLine.tsx(11,17): error TS7006: Parameter 'id' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesInvoiceLine.tsx(11,21): error TS7006: Parameter 'itemId' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesInvoiceLine.tsx(11,29): error TS7006: Parameter 'measurementId' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesInvoiceLine.tsx(11,44): error TS7006: Parameter 'quantity' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesInvoiceLine.tsx(11,54): error TS7006: Parameter 'amount' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesInvoiceLine.tsx(11,62): error TS7006: Parameter 'discount' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesInvoiceLine.tsx(11,72): error TS7006: Parameter 'code' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(1,39): error TS6133: 'action' is declared but its value is never read. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(1,56): error TS6133: 'computed' is declared but its value is never read. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(18,17): error TS7008: Member 'validationErrors' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(22,17): error TS7006: Parameter 'orderId' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(22,26): error TS7006: Parameter 'invoiceId' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(40,34): error TS7006: Parameter 'result' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(45,21): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(54,17): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(55,17): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(56,17): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(57,17): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(58,17): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(59,17): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(60,17): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(65,34): error TS7006: Parameter 'result' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(67,21): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(75,21): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(75,52): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(78,17): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(79,17): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(80,17): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(81,17): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(82,17): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(83,17): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(84,17): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(85,17): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(87,29): error TS2531: Object is possibly 'null'. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(105,13): error TS6133: 'gtotal' is declared but its value is never read. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(111,33): error TS7006: Parameter 'result' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(113,43): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(115,21): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(116,21): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(125,13): error TS2322: Type 'string' is not assignable to type 'Date'. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(134,33): error TS6133: 'response' is declared but its value is never read. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(137,34): error TS7006: Parameter 'error' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(138,46): error TS7006: Parameter 'err' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(139,25): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(140,28): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(164,33): error TS6133: 'response' is declared but its value is never read. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(167,34): error TS7006: Parameter 'error' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(168,46): error TS7006: Parameter 'err' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(169,25): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(170,28): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(225,58): error TS6133: 'discount' is declared but its value is never read. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(243,58): error TS6133: 'discount' is declared but its value is never read. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(265,24): error TS7006: Parameter 'refNo' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(268,21): error TS7006: Parameter 'custId' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(272,24): error TS7006: Parameter 'date' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(276,24): error TS7006: Parameter 'termId' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(280,17): error TS7006: Parameter 'id' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(280,21): error TS7006: Parameter 'itemId' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(280,29): error TS7006: Parameter 'measurementId' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(280,44): error TS7006: Parameter 'quantity' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(280,54): error TS7006: Parameter 'amount' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(280,62): error TS7006: Parameter 'discount' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(280,72): error TS7006: Parameter 'code' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(285,20): error TS7006: Parameter 'row' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(289,20): error TS7006: Parameter 'row' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(289,25): error TS7006: Parameter 'targetProperty' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(289,41): error TS7006: Parameter 'value' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(291,13): error TS7053: Element implicitly has an 'any' type because expression of type 'any' can't be used to index type 'SalesInvoiceLine'. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(296,18): error TS7006: Parameter 'row' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(303,21): error TS7006: Parameter 'editMode' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(307,20): error TS7006: Parameter 'itemId' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(310,43): error TS2339: Property 'id' does not exist on type 'never'. +src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx(311,50): error TS2339: Property 'code' does not exist on type 'never'. +src/components/Shared/Stores/Sales/SalesOrder.tsx(13,5): error TS2564: Property 'id' has no initializer and is not definitely assigned in the constructor. +src/components/Shared/Stores/Sales/SalesOrder.tsx(14,5): error TS2564: Property 'customerId' has no initializer and is not definitely assigned in the constructor. +src/components/Shared/Stores/Sales/SalesOrder.tsx(15,5): error TS2564: Property 'orderDate' has no initializer and is not definitely assigned in the constructor. +src/components/Shared/Stores/Sales/SalesOrder.tsx(16,5): error TS2564: Property 'paymentTermId' has no initializer and is not definitely assigned in the constructor. +src/components/Shared/Stores/Sales/SalesOrder.tsx(17,5): error TS2564: Property 'referenceNo' has no initializer and is not definitely assigned in the constructor. +src/components/Shared/Stores/Sales/SalesOrder.tsx(18,5): error TS2564: Property 'statusId' has no initializer and is not definitely assigned in the constructor. +src/components/Shared/Stores/Sales/SalesOrder.tsx(19,5): error TS2564: Property 'quotationId' has no initializer and is not definitely assigned in the constructor. +src/components/Shared/Stores/Sales/SalesOrderLine.tsx(9,17): error TS7006: Parameter 'id' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesOrderLine.tsx(9,21): error TS7006: Parameter 'itemId' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesOrderLine.tsx(9,29): error TS7006: Parameter 'measurementId' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesOrderLine.tsx(9,44): error TS7006: Parameter 'quantity' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesOrderLine.tsx(9,54): error TS7006: Parameter 'amount' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesOrderLine.tsx(9,62): error TS7006: Parameter 'discount' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesOrderLine.tsx(9,72): error TS7006: Parameter 'code' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(1,39): error TS6133: 'action' is declared but its value is never read. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(1,56): error TS6133: 'computed' is declared but its value is never read. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(18,17): error TS7008: Member 'validationErrors' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(19,17): error TS7008: Member 'salesOrderStatus' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(20,17): error TS7008: Member 'salesQuotationStatus' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(23,17): error TS7006: Parameter 'quotationId' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(23,30): error TS7006: Parameter 'orderId' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(39,35): error TS7006: Parameter 'result' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(40,17): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(41,17): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(42,17): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(43,17): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(44,17): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(45,17): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(47,17): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(49,21): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(58,17): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(59,29): error TS2531: Object is possibly 'null'. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(67,35): error TS7006: Parameter 'result' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(68,17): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(69,17): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(70,17): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(71,17): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(72,17): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(73,17): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(75,21): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(83,21): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(83,52): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(85,17): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(86,29): error TS2531: Object is possibly 'null'. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(105,13): error TS6133: 'gtotal' is declared but its value is never read. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(111,33): error TS7006: Parameter 'result' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(113,43): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(115,21): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(116,21): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(126,13): error TS2322: Type 'string' is not assignable to type 'Date'. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(136,33): error TS6133: 'response' is declared but its value is never read. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(139,34): error TS7006: Parameter 'error' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(140,46): error TS7006: Parameter 'err' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(141,25): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(142,28): error TS2683: 'this' implicitly has type 'any' because it does not have a type annotation. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(197,58): error TS6133: 'discount' is declared but its value is never read. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(215,58): error TS6133: 'discount' is declared but its value is never read. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(236,24): error TS7006: Parameter 'statusId' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(252,20): error TS7006: Parameter 'statusId' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(271,20): error TS7006: Parameter 'itemId' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(274,43): error TS2339: Property 'id' does not exist on type 'never'. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(275,50): error TS2339: Property 'code' does not exist on type 'never'. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(280,24): error TS7006: Parameter 'refNo' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(283,21): error TS7006: Parameter 'custId' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(287,22): error TS7006: Parameter 'date' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(291,24): error TS7006: Parameter 'termId' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(295,17): error TS7006: Parameter 'id' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(295,21): error TS7006: Parameter 'itemId' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(295,29): error TS7006: Parameter 'measurementId' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(295,44): error TS7006: Parameter 'quantity' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(295,54): error TS7006: Parameter 'amount' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(295,62): error TS7006: Parameter 'discount' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(295,72): error TS7006: Parameter 'code' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(300,20): error TS7006: Parameter 'row' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(304,20): error TS7006: Parameter 'row' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(304,25): error TS7006: Parameter 'targetProperty' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(304,41): error TS7006: Parameter 'value' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(306,13): error TS7053: Element implicitly has an 'any' type because expression of type 'any' can't be used to index type 'SalesOrderLine'. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(311,18): error TS7006: Parameter 'row' implicitly has an 'any' type. +src/components/Shared/Stores/Sales/SalesOrderStore.tsx(318,21): error TS7006: Parameter 'editMode' implicitly has an 'any' type. +src/components/Shared/Stores/TaxSystem/Tax.tsx(2,5): error TS2564: Property 'id' has no initializer and is not definitely assigned in the constructor. +src/components/Shared/Stores/TaxSystem/Tax.tsx(3,5): error TS2564: Property 'code' has no initializer and is not definitely assigned in the constructor. +src/components/Shared/Stores/TaxSystem/Tax.tsx(4,5): error TS2564: Property 'name' has no initializer and is not definitely assigned in the constructor. +src/components/Shared/Stores/TaxSystem/Tax.tsx(5,5): error TS2564: Property 'rate' has no initializer and is not definitely assigned in the constructor. diff --git a/src/GoodBooksReact/index.html b/src/GoodBooksReact/index.html new file mode 100644 index 000000000..048d1d378 --- /dev/null +++ b/src/GoodBooksReact/index.html @@ -0,0 +1,13 @@ + + + + + + + Vite + React + TS + + +
    + + + diff --git a/src/GoodBooksReact/package-lock.json b/src/GoodBooksReact/package-lock.json new file mode 100644 index 000000000..1dcc65fba --- /dev/null +++ b/src/GoodBooksReact/package-lock.json @@ -0,0 +1,8113 @@ +{ + "name": "goodbooksreact", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "goodbooksreact", + "version": "0.0.0", + "dependencies": { + "accounting": "^0.4.1", + "ag-grid": "^18.1.2", + "d3": "^7.8.5", + "font-awesome": "^4.7.0", + "jspdf": "^2.5.1", + "pace-progress": "^1.0.2", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-dom-factories": "^1.0.2", + "react-router": "^6.21.1", + "react-router-dom": "^6.21.1" + }, + "devDependencies": { + "@babel/core": "^7.23.6", + "@babel/plugin-proposal-decorators": "^7.23.6", + "@babel/plugin-syntax-decorators": "^7.23.3", + "@babel/preset-env": "^7.23.6", + "@coreui/coreui": "^4.3.2", + "@coreui/icons": "^3.0.1", + "@types/accounting": "^0.4.5", + "@types/react": "^18.2.43", + "@types/react-dom": "^18.2.17", + "@types/react-router": "^5.1.20", + "@types/react-router-dom": "^5.3.3", + "@typescript-eslint/eslint-plugin": "^6.14.0", + "@typescript-eslint/parser": "^6.14.0", + "@vitejs/plugin-react": "^4.2.1", + "ag-grid-community": "^31.0.1", + "ajv": "^8.12.0", + "axios": "^1.6.2", + "bootstrap": "^5.3.2", + "eslint": "^8.55.0", + "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-react-refresh": "^0.4.5", + "html2canvas": "^1.4.1", + "ionicons": "^7.2.2", + "jquery": "^3.7.1", + "mobx": "^6.12.0", + "mobx-react": "^9.1.0", + "perfect-scrollbar": "^1.5.5", + "popper.js": "^1.16.1", + "saas": "^1.0.0", + "simple-line-icons": "^2.5.5", + "ts-loader": "^9.5.1", + "tsd": "^0.30.0", + "typescript": "^5.2.2", + "vite": "^5.0.8", + "webpack": "^5.89.0", + "webpack-cli": "^5.1.4" + } + }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", + "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", + "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.23.4", + "chalk": "^2.4.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz", + "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.6.tgz", + "integrity": "sha512-FxpRyGjrMJXh7X3wGLGhNDCRiwpWEF74sKjTLDJSG5Kyvow3QZaG0Adbqzi9ZrVjTWpsX+2cxWXD71NMg93kdw==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.23.6", + "@babel/parser": "^7.23.6", + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.6", + "@babel/types": "^7.23.6", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", + "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.23.6", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", + "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.15.tgz", + "integrity": "sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", + "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.23.5", + "@babel/helper-validator-option": "^7.23.5", + "browserslist": "^4.22.2", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.23.6.tgz", + "integrity": "sha512-cBXU1vZni/CpGF29iTu4YRbOZt3Wat6zCoMDxRF1MayiEc4URxOj31tT65HUM0CRpMowA3HCJaAOVOUnMf96cw==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-member-expression-to-functions": "^7.23.0", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.20", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.15.tgz", + "integrity": "sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "regexpu-core": "^5.3.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.4.tgz", + "integrity": "sha512-QcJMILQCu2jm5TFPGA3lCpJJTeEP+mqeXooG/NZbg/h5FTFi6V0+99ahlRsW8/kRLyb24LZVCCiclDedhLKcBA==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "dev": true, + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz", + "integrity": "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", + "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz", + "integrity": "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.20.tgz", + "integrity": "sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-wrap-function": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.20.tgz", + "integrity": "sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-member-expression-to-functions": "^7.22.15", + "@babel/helper-optimise-call-expression": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz", + "integrity": "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", + "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", + "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.20.tgz", + "integrity": "sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw==", + "dev": true, + "dependencies": { + "@babel/helper-function-name": "^7.22.5", + "@babel/template": "^7.22.15", + "@babel/types": "^7.22.19" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.6.tgz", + "integrity": "sha512-wCfsbN4nBidDRhpDhvcKlzHWCTlgJYUUdSJfzXb2NuBssDSIjc3xcb+znA7l+zYsFljAcGM0aFkN40cR3lXiGA==", + "dev": true, + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.6", + "@babel/types": "^7.23.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", + "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.6.tgz", + "integrity": "sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.23.3.tgz", + "integrity": "sha512-iRkKcCqb7iGnq9+3G6rZ+Ciz5VywC4XNRHe57lKM+jOeYAoR0lVqdeeDRfh0tQcTfw/+vBhHn926FmQhLtlFLQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.23.3.tgz", + "integrity": "sha512-WwlxbfMNdVEpQjZmK5mhm7oSwD3dS6eU+Iwsi4Knl9wAletWem7kaRsGOG+8UEbRyqxY4SS5zvtfXwX+jMxUwQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-transform-optional-chaining": "^7.23.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.23.3.tgz", + "integrity": "sha512-XaJak1qcityzrX0/IU5nKHb34VaibwP3saKqG6a/tppelgllOH13LUann4ZCIBcVOeE6H18K4Vx9QKkVww3z/w==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-proposal-decorators": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.23.6.tgz", + "integrity": "sha512-D7Ccq9LfkBFnow3azZGJvZYgcfeqAw3I1e5LoTpj6UKIFQilh8yqXsIGcRIqbBdsPWIz+Ze7ZZfggSj62Qp+Fg==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.23.6", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.20", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/plugin-syntax-decorators": "^7.23.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-decorators": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.23.3.tgz", + "integrity": "sha512-cf7Niq4/+/juY67E0PbgH0TDhLQ5J7zS8C/Q5FFx+DWyrRa9sUQdTXkjqKu8zGvuqr7vw1muKiukseihU+PJDA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.23.3.tgz", + "integrity": "sha512-lPgDSU+SJLK3xmFDTV2ZRQAiM7UuUjGidwBywFavObCiZc1BeAAcMtHJKUya92hPHO+at63JJPLygilZard8jw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.23.3.tgz", + "integrity": "sha512-pawnE0P9g10xgoP7yKr6CK63K2FMsTE+FZidZO/1PwRdzmAPVs+HS1mAURUsgaoxammTJvULUdIkEK0gOcU2tA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.23.3.tgz", + "integrity": "sha512-NzQcQrzaQPkaEwoTm4Mhyl8jI1huEL/WWIEvudjTCMJ9aBZNpsJbMASx7EQECtQQPS/DcnFpo0FIh3LvEO9cxQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.23.4.tgz", + "integrity": "sha512-efdkfPhHYTtn0G6n2ddrESE91fgXxjlqLsnUtPWnJs4a4mZIbUaK7ffqKIIUKXSHwcDvaCVX6GXkaJJFqtX7jw==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.20", + "@babel/plugin-syntax-async-generators": "^7.8.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.23.3.tgz", + "integrity": "sha512-A7LFsKi4U4fomjqXJlZg/u0ft/n8/7n7lpffUP/ZULx/DtV9SGlNKZolHH6PE8Xl1ngCc0M11OaeZptXVkfKSw==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.23.3.tgz", + "integrity": "sha512-vI+0sIaPIO6CNuM9Kk5VmXcMVRiOpDh7w2zZt9GXzmE/9KD70CUEVhvPR/etAeNK/FAEkhxQtXOzVF3EuRL41A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.23.4.tgz", + "integrity": "sha512-0QqbP6B6HOh7/8iNR4CQU2Th/bbRtBp4KS9vcaZd1fZ0wSh5Fyssg0UCIHwxh+ka+pNDREbVLQnHCMHKZfPwfw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.23.3.tgz", + "integrity": "sha512-uM+AN8yCIjDPccsKGlw271xjJtGii+xQIF/uMPS8H15L12jZTsLfF4o5vNO7d/oUguOyfdikHGc/yi9ge4SGIg==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.23.4.tgz", + "integrity": "sha512-nsWu/1M+ggti1SOALj3hfx5FXzAY06fwPJsUZD4/A5e1bWi46VUIWtD+kOX6/IdhXGsXBWllLFDSnqSCdUNydQ==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.23.5.tgz", + "integrity": "sha512-jvOTR4nicqYC9yzOHIhXG5emiFEOpappSJAl73SDSEDcybD+Puuze8Tnpb9p9qEyYup24tq891gkaygIFvWDqg==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.20", + "@babel/helper-split-export-declaration": "^7.22.6", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.23.3.tgz", + "integrity": "sha512-dTj83UVTLw/+nbiHqQSFdwO9CbTtwq1DsDqm3CUEtDrZNET5rT5E6bIdTlOftDTDLMYxvxHNEYO4B9SLl8SLZw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/template": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.23.3.tgz", + "integrity": "sha512-n225npDqjDIr967cMScVKHXJs7rout1q+tt50inyBCPkyZ8KxeI6d+GIbSBTT/w/9WdlWDOej3V9HE5Lgk57gw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.23.3.tgz", + "integrity": "sha512-vgnFYDHAKzFaTVp+mneDsIEbnJ2Np/9ng9iviHw3P/KVcgONxpNULEW/51Z/BaFojG2GI2GwwXck5uV1+1NOYQ==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.23.3.tgz", + "integrity": "sha512-RrqQ+BQmU3Oyav3J+7/myfvRCq7Tbz+kKLLshUmMwNlDHExbGL7ARhajvoBJEvc+fCguPPu887N+3RRXBVKZUA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.23.4.tgz", + "integrity": "sha512-V6jIbLhdJK86MaLh4Jpghi8ho5fGzt3imHOBu/x0jlBaPYqDoWz4RDXjmMOfnh+JWNaQleEAByZLV0QzBT4YQQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.23.3.tgz", + "integrity": "sha512-5fhCsl1odX96u7ILKHBj4/Y8vipoqwsJMh4csSA8qFfxrZDEA4Ssku2DyNvMJSmZNOEBT750LfFPbtrnTP90BQ==", + "dev": true, + "dependencies": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.23.4.tgz", + "integrity": "sha512-GzuSBcKkx62dGzZI1WVgTWvkkz84FZO5TC5T8dl/Tht/rAla6Dg/Mz9Yhypg+ezVACf/rgDuQt3kbWEv7LdUDQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.23.6.tgz", + "integrity": "sha512-aYH4ytZ0qSuBbpfhuofbg/e96oQ7U2w1Aw/UQmKT+1l39uEhUPoFS3fHevDc1G0OvewyDudfMKY1OulczHzWIw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.23.3.tgz", + "integrity": "sha512-I1QXp1LxIvt8yLaib49dRW5Okt7Q4oaxao6tFVKS/anCdEOMtYwWVKoiOA1p34GOWIZjUK0E+zCp7+l1pfQyiw==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.23.4.tgz", + "integrity": "sha512-81nTOqM1dMwZ/aRXQ59zVubN9wHGqk6UtqRK+/q+ciXmRy8fSolhGVvG09HHRGo4l6fr/c4ZhXUQH0uFW7PZbg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-json-strings": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.23.3.tgz", + "integrity": "sha512-wZ0PIXRxnwZvl9AYpqNUxpZ5BiTGrYt7kueGQ+N5FiQ7RCOD4cm8iShd6S6ggfVIWaJf2EMk8eRzAh52RfP4rQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.23.4.tgz", + "integrity": "sha512-Mc/ALf1rmZTP4JKKEhUwiORU+vcfarFVLfcFiolKUo6sewoxSEgl36ak5t+4WamRsNr6nzjZXQjM35WsU+9vbg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.23.3.tgz", + "integrity": "sha512-sC3LdDBDi5x96LA+Ytekz2ZPk8i/Ck+DEuDbRAll5rknJ5XRTSaPKEYwomLcs1AA8wg9b3KjIQRsnApj+q51Ag==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.23.3.tgz", + "integrity": "sha512-vJYQGxeKM4t8hYCKVBlZX/gtIY2I7mRGFNcm85sgXGMTBcoV3QdVtdpbcWEbzbfUIUZKwvgFT82mRvaQIebZzw==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.23.3.tgz", + "integrity": "sha512-aVS0F65LKsdNOtcz6FRCpE4OgsP2OFnW46qNxNIX9h3wuzaNcSQsJysuMwqSibC98HPrf2vCgtxKNwS0DAlgcA==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-simple-access": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.23.3.tgz", + "integrity": "sha512-ZxyKGTkF9xT9YJuKQRo19ewf3pXpopuYQd8cDXqNzc3mUNbOME0RKMoZxviQk74hwzfQsEe66dE92MaZbdHKNQ==", + "dev": true, + "dependencies": { + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.23.3.tgz", + "integrity": "sha512-zHsy9iXX2nIsCBFPud3jKn1IRPWg3Ing1qOZgeKV39m1ZgIdpJqvlWVeiHBZC6ITRG0MfskhYe9cLgntfSFPIg==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz", + "integrity": "sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.23.3.tgz", + "integrity": "sha512-YJ3xKqtJMAT5/TIZnpAR3I+K+WaDowYbN3xyxI8zxx/Gsypwf9B9h0VB+1Nh6ACAAPRS5NSRje0uVv5i79HYGQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.23.4.tgz", + "integrity": "sha512-jHE9EVVqHKAQx+VePv5LLGHjmHSJR76vawFPTdlxR/LVJPfOEGxREQwQfjuZEOPTwG92X3LINSh3M40Rv4zpVA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.23.4.tgz", + "integrity": "sha512-mps6auzgwjRrwKEZA05cOwuDc9FAzoyFS4ZsG/8F43bTLf/TgkJg7QXOrPO1JO599iA3qgK9MXdMGOEC8O1h6Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.23.4.tgz", + "integrity": "sha512-9x9K1YyeQVw0iOXJlIzwm8ltobIIv7j2iLyP2jIhEbqPRQ7ScNgwQufU2I0Gq11VjyG4gI4yMXt2VFags+1N3g==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.23.3", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.23.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.23.3.tgz", + "integrity": "sha512-BwQ8q0x2JG+3lxCVFohg+KbQM7plfpBwThdW9A6TMtWwLsbDA01Ek2Zb/AgDN39BiZsExm4qrXxjk+P1/fzGrA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.23.4.tgz", + "integrity": "sha512-XIq8t0rJPHf6Wvmbn9nFxU6ao4c7WhghTR5WyV8SrJfUFzyxhCm4nhC+iAp3HFhbAKLfYpgzhJ6t4XCtVwqO5A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.23.4.tgz", + "integrity": "sha512-ZU8y5zWOfjM5vZ+asjgAPwDaBjJzgufjES89Rs4Lpq63O300R/kOz30WCLo6BxxX6QVEilwSlpClnG5cZaikTA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.23.3.tgz", + "integrity": "sha512-09lMt6UsUb3/34BbECKVbVwrT9bO6lILWln237z7sLaWnMsTi7Yc9fhX5DLpkJzAGfaReXI22wP41SZmnAA3Vw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.23.3.tgz", + "integrity": "sha512-UzqRcRtWsDMTLrRWFvUBDwmw06tCQH9Rl1uAjfh6ijMSmGYQ+fpdB+cnqRC8EMh5tuuxSv0/TejGL+7vyj+50g==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.23.4.tgz", + "integrity": "sha512-9G3K1YqTq3F4Vt88Djx1UZ79PDyj+yKRnUy7cZGSMe+a7jkwD259uKKuUzQlPkGam7R+8RJwh5z4xO27fA1o2A==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.23.3.tgz", + "integrity": "sha512-jR3Jn3y7cZp4oEWPFAlRsSWjxKe4PZILGBSd4nis1TsC5qeSpb+nrtihJuDhNI7QHiVbUaiXa0X2RZY3/TI6Nw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.23.3.tgz", + "integrity": "sha512-qXRvbeKDSfwnlJnanVRp0SfuWE5DQhwQr5xtLBzp56Wabyo+4CMosF6Kfp+eOD/4FYpql64XVJ2W0pVLlJZxOQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.23.3.tgz", + "integrity": "sha512-91RS0MDnAWDNvGC6Wio5XYkyWI39FMFO+JK9+4AlgaTH+yWwVTsw7/sn6LK0lH7c5F+TFkpv/3LfCJ1Ydwof/g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.23.3.tgz", + "integrity": "sha512-KP+75h0KghBMcVpuKisx3XTu9Ncut8Q8TuvGO4IhY+9D5DFEckQefOuIsB/gQ2tG71lCke4NMrtIPS8pOj18BQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "regenerator-transform": "^0.15.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.23.3.tgz", + "integrity": "sha512-QnNTazY54YqgGxwIexMZva9gqbPa15t/x9VS+0fsEFWplwVpXYZivtgl43Z1vMpc1bdPP2PP8siFeVcnFvA3Cg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.23.3.tgz", + "integrity": "sha512-ED2fgqZLmexWiN+YNFX26fx4gh5qHDhn1O2gvEhreLW2iI63Sqm4llRLCXALKrCnbN4Jy0VcMQZl/SAzqug/jg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.23.3.tgz", + "integrity": "sha512-VvfVYlrlBVu+77xVTOAoxQ6mZbnIq5FM0aGBSFEcIh03qHf+zNqA4DC/3XMUozTg7bZV3e3mZQ0i13VB6v5yUg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.23.3.tgz", + "integrity": "sha512-HZOyN9g+rtvnOU3Yh7kSxXrKbzgrm5X4GncPY1QOquu7epga5MxKHVpYu2hvQnry/H+JjckSYRb93iNfsioAGg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.23.3.tgz", + "integrity": "sha512-Flok06AYNp7GV2oJPZZcP9vZdszev6vPBkHLwxwSpaIqx75wn6mUd3UFWsSsA0l8nXAKkyCmL/sR02m8RYGeHg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.23.3.tgz", + "integrity": "sha512-4t15ViVnaFdrPC74be1gXBSMzXk3B4Us9lP7uLRQHTFpV5Dvt33pn+2MyyNxmN3VTTm3oTrZVMUmuw3oBnQ2oQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.23.3.tgz", + "integrity": "sha512-OMCUx/bU6ChE3r4+ZdylEqAjaQgHAgipgW8nsCfu5pGqDcFytVd91AwRvUJSBZDz0exPGgnjoqhgRYLRjFZc9Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.23.3.tgz", + "integrity": "sha512-KcLIm+pDZkWZQAFJ9pdfmh89EwVfmNovFBcXko8szpBeF8z68kWIPeKlmSOkT9BXJxs2C0uk+5LxoxIv62MROA==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.23.3.tgz", + "integrity": "sha512-wMHpNA4x2cIA32b/ci3AfwNgheiva2W0WUKWTK7vBHBhDKfPsc5cFGNWm69WBqpwd86u1qwZ9PWevKqm1A3yAw==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.23.3.tgz", + "integrity": "sha512-W7lliA/v9bNR83Qc3q1ip9CQMZ09CcHDbHfbLRDNuAhn1Mvkr1ZNF7hPmztMQvtTGVLJ9m8IZqWsTkXOml8dbw==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.23.6.tgz", + "integrity": "sha512-2XPn/BqKkZCpzYhUUNZ1ssXw7DcXfKQEjv/uXZUXgaebCMYmkEsfZ2yY+vv+xtXv50WmL5SGhyB6/xsWxIvvOQ==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.23.5", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-option": "^7.23.5", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.23.3", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.23.3", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.23.3", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.23.3", + "@babel/plugin-syntax-import-attributes": "^7.23.3", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.23.3", + "@babel/plugin-transform-async-generator-functions": "^7.23.4", + "@babel/plugin-transform-async-to-generator": "^7.23.3", + "@babel/plugin-transform-block-scoped-functions": "^7.23.3", + "@babel/plugin-transform-block-scoping": "^7.23.4", + "@babel/plugin-transform-class-properties": "^7.23.3", + "@babel/plugin-transform-class-static-block": "^7.23.4", + "@babel/plugin-transform-classes": "^7.23.5", + "@babel/plugin-transform-computed-properties": "^7.23.3", + "@babel/plugin-transform-destructuring": "^7.23.3", + "@babel/plugin-transform-dotall-regex": "^7.23.3", + "@babel/plugin-transform-duplicate-keys": "^7.23.3", + "@babel/plugin-transform-dynamic-import": "^7.23.4", + "@babel/plugin-transform-exponentiation-operator": "^7.23.3", + "@babel/plugin-transform-export-namespace-from": "^7.23.4", + "@babel/plugin-transform-for-of": "^7.23.6", + "@babel/plugin-transform-function-name": "^7.23.3", + "@babel/plugin-transform-json-strings": "^7.23.4", + "@babel/plugin-transform-literals": "^7.23.3", + "@babel/plugin-transform-logical-assignment-operators": "^7.23.4", + "@babel/plugin-transform-member-expression-literals": "^7.23.3", + "@babel/plugin-transform-modules-amd": "^7.23.3", + "@babel/plugin-transform-modules-commonjs": "^7.23.3", + "@babel/plugin-transform-modules-systemjs": "^7.23.3", + "@babel/plugin-transform-modules-umd": "^7.23.3", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5", + "@babel/plugin-transform-new-target": "^7.23.3", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.23.4", + "@babel/plugin-transform-numeric-separator": "^7.23.4", + "@babel/plugin-transform-object-rest-spread": "^7.23.4", + "@babel/plugin-transform-object-super": "^7.23.3", + "@babel/plugin-transform-optional-catch-binding": "^7.23.4", + "@babel/plugin-transform-optional-chaining": "^7.23.4", + "@babel/plugin-transform-parameters": "^7.23.3", + "@babel/plugin-transform-private-methods": "^7.23.3", + "@babel/plugin-transform-private-property-in-object": "^7.23.4", + "@babel/plugin-transform-property-literals": "^7.23.3", + "@babel/plugin-transform-regenerator": "^7.23.3", + "@babel/plugin-transform-reserved-words": "^7.23.3", + "@babel/plugin-transform-shorthand-properties": "^7.23.3", + "@babel/plugin-transform-spread": "^7.23.3", + "@babel/plugin-transform-sticky-regex": "^7.23.3", + "@babel/plugin-transform-template-literals": "^7.23.3", + "@babel/plugin-transform-typeof-symbol": "^7.23.3", + "@babel/plugin-transform-unicode-escapes": "^7.23.3", + "@babel/plugin-transform-unicode-property-regex": "^7.23.3", + "@babel/plugin-transform-unicode-regex": "^7.23.3", + "@babel/plugin-transform-unicode-sets-regex": "^7.23.3", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.6", + "babel-plugin-polyfill-corejs3": "^0.8.5", + "babel-plugin-polyfill-regenerator": "^0.5.3", + "core-js-compat": "^3.31.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==", + "dev": true + }, + "node_modules/@babel/runtime": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.6.tgz", + "integrity": "sha512-zHd0eUrf5GZoOWVCXp6koAKQTfZV07eit6bGPmJgnZdnSAvvZee6zniW2XMF7Cmc4ISOOnPy3QaSiIJGJkVEDQ==", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.6.tgz", + "integrity": "sha512-czastdK1e8YByZqezMPFiZ8ahwVMh/ESl9vPgvgdB9AmFMGP5jfpFax74AQgl5zj4XHzqeYAg2l8PuUeRS1MgQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.6", + "@babel/types": "^7.23.6", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.6.tgz", + "integrity": "sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@coreui/coreui": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@coreui/coreui/-/coreui-4.3.2.tgz", + "integrity": "sha512-SKGY6E6v7QGq0P3YTnZQRSrU8t0euLQ3UV/FH5j0JmHYBBu7Mv0Hd9g8AESnj8xrCelKZ5bdZKZhmKaIdG5clw==", + "dev": true, + "dependencies": { + "postcss-combine-duplicated-selectors": "^10.0.3" + }, + "peerDependencies": { + "@popperjs/core": "^2.11.6" + } + }, + "node_modules/@coreui/icons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@coreui/icons/-/icons-3.0.1.tgz", + "integrity": "sha512-u9UKEcRMyY9pa4jUoLij8pAR03g5g6TLWV33/Mx2ix8sffyi0eO4fLV8DSTQljDCw938zt7KYog5cVKEAJUxxg==", + "dev": true + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.10.tgz", + "integrity": "sha512-Q+mk96KJ+FZ30h9fsJl+67IjNJm3x2eX+GBWGmocAKgzp27cowCOOqSdscX80s0SpdFXZnIv/+1xD1EctFx96Q==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.10.tgz", + "integrity": "sha512-7W0bK7qfkw1fc2viBfrtAEkDKHatYfHzr/jKAHNr9BvkYDXPcC6bodtm8AyLJNNuqClLNaeTLuwURt4PRT9d7w==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.10.tgz", + "integrity": "sha512-1X4CClKhDgC3by7k8aOWZeBXQX8dHT5QAMCAQDArCLaYfkppoARvh0fit3X2Qs+MXDngKcHv6XXyQCpY0hkK1Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.10.tgz", + "integrity": "sha512-O/nO/g+/7NlitUxETkUv/IvADKuZXyH4BHf/g/7laqKC4i/7whLpB0gvpPc2zpF0q9Q6FXS3TS75QHac9MvVWw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.10.tgz", + "integrity": "sha512-YSRRs2zOpwypck+6GL3wGXx2gNP7DXzetmo5pHXLrY/VIMsS59yKfjPizQ4lLt5vEI80M41gjm2BxrGZ5U+VMA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.10.tgz", + "integrity": "sha512-alfGtT+IEICKtNE54hbvPg13xGBe4GkVxyGWtzr+yHO7HIiRJppPDhOKq3zstTcVf8msXb/t4eavW3jCDpMSmA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.10.tgz", + "integrity": "sha512-dMtk1wc7FSH8CCkE854GyGuNKCewlh+7heYP/sclpOG6Cectzk14qdUIY5CrKDbkA/OczXq9WesqnPl09mj5dg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.10.tgz", + "integrity": "sha512-G5UPPspryHu1T3uX8WiOEUa6q6OlQh6gNl4CO4Iw5PS+Kg5bVggVFehzXBJY6X6RSOMS8iXDv2330VzaObm4Ag==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.10.tgz", + "integrity": "sha512-j6gUW5aAaPgD416Hk9FHxn27On28H4eVI9rJ4az7oCGTFW48+LcgNDBN+9f8rKZz7EEowo889CPKyeaD0iw9Kg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.10.tgz", + "integrity": "sha512-QxaouHWZ+2KWEj7cGJmvTIHVALfhpGxo3WLmlYfJ+dA5fJB6lDEIg+oe/0//FuyVHuS3l79/wyBxbHr0NgtxJQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.10.tgz", + "integrity": "sha512-4ub1YwXxYjj9h1UIZs2hYbnTZBtenPw5NfXCRgEkGb0b6OJ2gpkMvDqRDYIDRjRdWSe/TBiZltm3Y3Q8SN1xNg==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.10.tgz", + "integrity": "sha512-lo3I9k+mbEKoxtoIbM0yC/MZ1i2wM0cIeOejlVdZ3D86LAcFXFRdeuZmh91QJvUTW51bOK5W2BznGNIl4+mDaA==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.10.tgz", + "integrity": "sha512-J4gH3zhHNbdZN0Bcr1QUGVNkHTdpijgx5VMxeetSk6ntdt+vR1DqGmHxQYHRmNb77tP6GVvD+K0NyO4xjd7y4A==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.10.tgz", + "integrity": "sha512-tgT/7u+QhV6ge8wFMzaklOY7KqiyitgT1AUHMApau32ZlvTB/+efeCtMk4eXS+uEymYK249JsoiklZN64xt6oQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.10.tgz", + "integrity": "sha512-0f/spw0PfBMZBNqtKe5FLzBDGo0SKZKvMl5PHYQr3+eiSscfJ96XEknCe+JoOayybWUFQbcJTrk946i3j9uYZA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.10.tgz", + "integrity": "sha512-pZFe0OeskMHzHa9U38g+z8Yx5FNCLFtUnJtQMpwhS+r4S566aK2ci3t4NCP4tjt6d5j5uo4h7tExZMjeKoehAA==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.10.tgz", + "integrity": "sha512-SpYNEqg/6pZYoc+1zLCjVOYvxfZVZj6w0KROZ3Fje/QrM3nfvT2llI+wmKSrWuX6wmZeTapbarvuNNK/qepSgA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.10.tgz", + "integrity": "sha512-ACbZ0vXy9zksNArWlk2c38NdKg25+L9pr/mVaj9SUq6lHZu/35nx2xnQVRGLrC1KKQqJKRIB0q8GspiHI3J80Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.10.tgz", + "integrity": "sha512-PxcgvjdSjtgPMiPQrM3pwSaG4kGphP+bLSb+cihuP0LYdZv1epbAIecHVl5sD3npkfYBZ0ZnOjR878I7MdJDFg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.10.tgz", + "integrity": "sha512-ZkIOtrRL8SEJjr+VHjmW0znkPs+oJXhlJbNwfI37rvgeMtk3sxOQevXPXjmAPZPigVTncvFqLMd+uV0IBSEzqA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.10.tgz", + "integrity": "sha512-+Sa4oTDbpBfGpl3Hn3XiUe4f8TU2JF7aX8cOfqFYMMjXp6ma6NJDztl5FDG8Ezx0OjwGikIHw+iA54YLDNNVfw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.10.tgz", + "integrity": "sha512-EOGVLK1oWMBXgfttJdPHDTiivYSjX6jDNaATeNOaCOFEVcfMjtbx7WVQwPSE1eIfCp/CaSF2nSrDtzc4I9f8TQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.10.tgz", + "integrity": "sha512-whqLG6Sc70AbU73fFYvuYzaE4MNMBIlR1Y/IrUeOXFrWHxBEjjbZaQ3IXIQS8wJdAzue2GwYZCjOrgrU1oUHoA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/@eslint/js": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz", + "integrity": "sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.13", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", + "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", + "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", + "dev": true + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", + "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "dev": true, + "peer": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@remix-run/router": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.14.1.tgz", + "integrity": "sha512-Qg4DMQsfPNAs88rb2xkdk03N3bjK4jgX5fR24eHCTR9q6PrhZQZ4UJBPzCHJkIpTRN1UKxx2DzjZmnC+7Lj0Ow==", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.9.1.tgz", + "integrity": "sha512-6vMdBZqtq1dVQ4CWdhFwhKZL6E4L1dV6jUjuBvsavvNJSppzi6dLBbuV+3+IyUREaj9ZFvQefnQm28v4OCXlig==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.9.1.tgz", + "integrity": "sha512-Jto9Fl3YQ9OLsTDWtLFPtaIMSL2kwGyGoVCmPC8Gxvym9TCZm4Sie+cVeblPO66YZsYH8MhBKDMGZ2NDxuk/XQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.9.1.tgz", + "integrity": "sha512-LtYcLNM+bhsaKAIGwVkh5IOWhaZhjTfNOkGzGqdHvhiCUVuJDalvDxEdSnhFzAn+g23wgsycmZk1vbnaibZwwA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.9.1.tgz", + "integrity": "sha512-KyP/byeXu9V+etKO6Lw3E4tW4QdcnzDG/ake031mg42lob5tN+5qfr+lkcT/SGZaH2PdW4Z1NX9GHEkZ8xV7og==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.9.1.tgz", + "integrity": "sha512-Yqz/Doumf3QTKplwGNrCHe/B2p9xqDghBZSlAY0/hU6ikuDVQuOUIpDP/YcmoT+447tsZTmirmjgG3znvSCR0Q==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.9.1.tgz", + "integrity": "sha512-u3XkZVvxcvlAOlQJ3UsD1rFvLWqu4Ef/Ggl40WAVCuogf4S1nJPHh5RTgqYFpCOvuGJ7H5yGHabjFKEZGExk5Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.9.1.tgz", + "integrity": "sha512-0XSYN/rfWShW+i+qjZ0phc6vZ7UWI8XWNz4E/l+6edFt+FxoEghrJHjX1EY/kcUGCnZzYYRCl31SNdfOi450Aw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.9.1.tgz", + "integrity": "sha512-LmYIO65oZVfFt9t6cpYkbC4d5lKHLYv5B4CSHRpnANq0VZUQXGcCPXHzbCXCz4RQnx7jvlYB1ISVNCE/omz5cw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.9.1.tgz", + "integrity": "sha512-kr8rEPQ6ns/Lmr/hiw8sEVj9aa07gh1/tQF2Y5HrNCCEPiCBGnBUt9tVusrcBBiJfIt1yNaXN6r1CCmpbFEDpg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.9.1.tgz", + "integrity": "sha512-t4QSR7gN+OEZLG0MiCgPqMWZGwmeHhsM4AkegJ0Kiy6TnJ9vZ8dEIwHw1LcZKhbHxTY32hp9eVCMdR3/I8MGRw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.9.1.tgz", + "integrity": "sha512-7XI4ZCBN34cb+BH557FJPmh0kmNz2c25SCQeT9OiFWEgf8+dL6ZwJ8f9RnUIit+j01u07Yvrsuu1rZGxJCc51g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.9.1.tgz", + "integrity": "sha512-yE5c2j1lSWOH5jp+Q0qNL3Mdhr8WuqCNVjc6BxbVfS5cAS6zRmdiw7ktb8GNpDCEUJphILY6KACoFoRtKoqNQg==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.9.1.tgz", + "integrity": "sha512-PyJsSsafjmIhVgaI1Zdj7m8BB8mMckFah/xbpplObyHfiXzKcI5UOUXRyOdHW7nz4DpMCuzLnF7v5IWHenCwYA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true + }, + "node_modules/@stencil/core": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@stencil/core/-/core-4.9.0.tgz", + "integrity": "sha512-aWSkhBmk3yPwRAkUwBbzRwmdhb8hKiQ/JMr9m5jthpBZLjtppYbzz6PN2MhSMDfRp6K93eQw5WogSEH4HHuB6w==", + "dev": true, + "bin": { + "stencil": "bin/stencil" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=7.10.0" + } + }, + "node_modules/@tsd/typescript": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@tsd/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-CQlfzol0ldaU+ftWuG52vH29uRoKboLinLy84wS8TQOu+m+tWoaUfk4svL4ij2V8M5284KymJBlHUusKj6k34w==", + "dev": true, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/@types/accounting": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/@types/accounting/-/accounting-0.4.5.tgz", + "integrity": "sha512-rf3MKoFZ3REGY2aQTqGwo79aJKom1xgHiJVBy0RguTqpxny1nDT4iYeLx2EgDEkXAhgbwnuLUoxlg4RKHIB7fQ==", + "dev": true + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.8", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", + "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.4", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.4.tgz", + "integrity": "sha512-mSM/iKUk5fDDrEV/e83qY+Cr3I1+Q3qqTuEn++HAWYjEa1+NxZr6CNrcJGf2ZTnq4HoFGC3zaTPZTobCzCFukA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "node_modules/@types/eslint": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.0.tgz", + "integrity": "sha512-FlsN0p4FhuYRjIxpbdXovvHQhtlG05O1GG/RNWvdAxTboR438IOTwmrY/vLA+Xfgg06BTkP045M3vpFwTMv1dg==", + "dev": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.7", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz", + "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==", + "dev": true, + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true + }, + "node_modules/@types/history": { + "version": "4.7.11", + "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz", + "integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==", + "dev": true + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, + "node_modules/@types/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.10.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.5.tgz", + "integrity": "sha512-nNPsNE65wjMxEKI93yOP+NPGGBJz/PoN3kZsVLee0XMiJolxSekEVD8wRwBUBqkwc7UWop0edW50yrCQW4CyRw==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/normalize-package-data": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", + "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", + "dev": true + }, + "node_modules/@types/prop-types": { + "version": "15.7.11", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.11.tgz", + "integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==", + "dev": true + }, + "node_modules/@types/raf": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/@types/raf/-/raf-3.4.3.tgz", + "integrity": "sha512-c4YAvMedbPZ5tEyxzQdMoOhhJ4RD3rngZIdwC2/qDN3d7JpEhB6fiBRKVY1lg5B7Wk+uPBjn5f39j1/2MY1oOw==", + "optional": true + }, + "node_modules/@types/react": { + "version": "18.2.45", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.45.tgz", + "integrity": "sha512-TtAxCNrlrBp8GoeEp1npd5g+d/OejJHFxS3OWmrPBMFaVQMSN0OFySozJio5BHxTuTeug00AVXVAjfDSfk+lUg==", + "dev": true, + "dependencies": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.2.18", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.18.tgz", + "integrity": "sha512-TJxDm6OfAX2KJWJdMEVTwWke5Sc/E/RlnPGvGfS0W7+6ocy2xhDVQVh/KvC2Uf7kACs+gDytdusDSdWfWkaNzw==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/react-router": { + "version": "5.1.20", + "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.20.tgz", + "integrity": "sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==", + "dev": true, + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*" + } + }, + "node_modules/@types/react-router-dom": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.3.tgz", + "integrity": "sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==", + "dev": true, + "dependencies": { + "@types/history": "^4.7.11", + "@types/react": "*", + "@types/react-router": "*" + } + }, + "node_modules/@types/scheduler": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz", + "integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==", + "dev": true + }, + "node_modules/@types/semver": { + "version": "7.5.6", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz", + "integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==", + "dev": true + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.15.0.tgz", + "integrity": "sha512-j5qoikQqPccq9QoBAupOP+CBu8BaJ8BLjaXSioDISeTZkVO3ig7oSIKh3H+rEpee7xCXtWwSB4KIL5l6hWZzpg==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.15.0", + "@typescript-eslint/type-utils": "6.15.0", + "@typescript-eslint/utils": "6.15.0", + "@typescript-eslint/visitor-keys": "6.15.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.15.0.tgz", + "integrity": "sha512-MkgKNnsjC6QwcMdlNAel24jjkEO/0hQaMDLqP4S9zq5HBAUJNQB6y+3DwLjX7b3l2b37eNAxMPLwb3/kh8VKdA==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "6.15.0", + "@typescript-eslint/types": "6.15.0", + "@typescript-eslint/typescript-estree": "6.15.0", + "@typescript-eslint/visitor-keys": "6.15.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.15.0.tgz", + "integrity": "sha512-+BdvxYBltqrmgCNu4Li+fGDIkW9n//NrruzG9X1vBzaNK+ExVXPoGB71kneaVw/Jp+4rH/vaMAGC6JfMbHstVg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.15.0", + "@typescript-eslint/visitor-keys": "6.15.0" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.15.0.tgz", + "integrity": "sha512-CnmHKTfX6450Bo49hPg2OkIm/D/TVYV7jO1MCfPYGwf6x3GO0VU8YMO5AYMn+u3X05lRRxA4fWCz87GFQV6yVQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "6.15.0", + "@typescript-eslint/utils": "6.15.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.15.0.tgz", + "integrity": "sha512-yXjbt//E4T/ee8Ia1b5mGlbNj9fB9lJP4jqLbZualwpP2BCQ5is6BcWwxpIsY4XKAhmdv3hrW92GdtJbatC6dQ==", + "dev": true, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.15.0.tgz", + "integrity": "sha512-7mVZJN7Hd15OmGuWrp2T9UvqR2Ecg+1j/Bp1jXUEY2GZKV6FXlOIoqVDmLpBiEiq3katvj/2n2mR0SDwtloCew==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.15.0", + "@typescript-eslint/visitor-keys": "6.15.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.15.0.tgz", + "integrity": "sha512-eF82p0Wrrlt8fQSRL0bGXzK5nWPRV2dYQZdajcfzOD9+cQz9O7ugifrJxclB+xVOvWvagXfqS4Es7vpLP4augw==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.15.0", + "@typescript-eslint/types": "6.15.0", + "@typescript-eslint/typescript-estree": "6.15.0", + "semver": "^7.5.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.15.0.tgz", + "integrity": "sha512-1zvtdC1a9h5Tb5jU9x3ADNXO9yjP8rXlaoChu0DQX40vf5ACVpYIVIZhIMZ6d5sDXH7vq4dsZBT1fEGj8D2n2w==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.15.0", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, + "node_modules/@vitejs/plugin-react": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.2.1.tgz", + "integrity": "sha512-oojO9IDc4nCUUi8qIR11KoQm0XFFLIwsRBwHRR4d/88IWghn1y6ckz/bJ8GHDCsYEJee8mDzqtJxh15/cisJNQ==", + "dev": true, + "dependencies": { + "@babel/core": "^7.23.5", + "@babel/plugin-transform-react-jsx-self": "^7.23.3", + "@babel/plugin-transform-react-jsx-source": "^7.23.3", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.14.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0" + } + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", + "integrity": "sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==", + "dev": true, + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz", + "integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", + "dev": true, + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz", + "integrity": "sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "dev": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "dev": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", + "dev": true + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz", + "integrity": "sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-opt": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6", + "@webassemblyjs/wast-printer": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz", + "integrity": "sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz", + "integrity": "sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz", + "integrity": "sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz", + "integrity": "sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webpack-cli/configtest": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.1.tgz", + "integrity": "sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/info": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.2.tgz", + "integrity": "sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + } + }, + "node_modules/@webpack-cli/serve": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.5.tgz", + "integrity": "sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==", + "dev": true, + "engines": { + "node": ">=14.15.0" + }, + "peerDependencies": { + "webpack": "5.x.x", + "webpack-cli": "5.x.x" + }, + "peerDependenciesMeta": { + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "node_modules/accounting": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/accounting/-/accounting-0.4.1.tgz", + "integrity": "sha512-RU6KY9Y5wllyaCNBo1W11ZOTnTHMMgOZkIwdOOs6W5ibMTp72i4xIbEA48djxVGqMNTUNbvrP/1nWg5Af5m2gQ==" + }, + "node_modules/acorn": { + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", + "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-assertions": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", + "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", + "dev": true, + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ag-grid": { + "version": "18.1.2", + "resolved": "https://registry.npmjs.org/ag-grid/-/ag-grid-18.1.2.tgz", + "integrity": "sha512-HtJt8iFcRKCBj5UHBDmwSLLr72F3XDACeBNarH4nJWFHIqcnu7u0Ifrd2nftPmfEBj6YjFHawDqcZL2yo3YfmQ==", + "deprecated": "ag-grid is now deprecated - please use @ag-grid-community/all-modules. See www.ag-grid.com/javascript-grid-modules/ for more information." + }, + "node_modules/ag-grid-community": { + "version": "31.0.1", + "resolved": "https://registry.npmjs.org/ag-grid-community/-/ag-grid-community-31.0.1.tgz", + "integrity": "sha512-RZQlW1DTOJHsUR/tnbnTJQKgAnDlHi05YYyTe5AgNor/1TlX1hoYdcqrGsJjvcHQgTjeEgzWOL0yf+KcqXZzxg==", + "dev": true + }, + "node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true + }, + "node_modules/atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "bin": { + "atob": "bin/atob.js" + }, + "engines": { + "node": ">= 4.5.0" + } + }, + "node_modules/axios": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.2.tgz", + "integrity": "sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==", + "dev": true, + "dependencies": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.7.tgz", + "integrity": "sha512-LidDk/tEGDfuHW2DWh/Hgo4rmnw3cduK6ZkOI1NPFceSK3n/yAGeOsNT7FLnSGHkXj3RHGSEVkN3FsCTY6w2CQ==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.4.4", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.8.7", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.7.tgz", + "integrity": "sha512-KyDvZYxAzkC0Aj2dAPyDzi2Ym15e5JKZSK+maI7NAwSqofvuFglbSsxE7wUOvTg9oFVnHMzVzBKcqEb4PJgtOA==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.4.4", + "core-js-compat": "^3.33.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.4.tgz", + "integrity": "sha512-S/x2iOCvDaCASLYsOOgWOq4bCfKYVqvO/uxjkaYyZ3rVsVE3CeAI/c84NpyuBBymEgNvHgjEot3a9/Z/kXvqsg==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.4.4" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/base64-arraybuffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", + "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==", + "devOptional": true, + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/bootstrap": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.2.tgz", + "integrity": "sha512-D32nmNWiQHo94BKHLmOrdjlL05q1c8oxbtBphQFb9Z5to6eGRDCm0QgeaZ4zFBHzfg2++rqa2JkqCcxDy0sH0g==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/twbs" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/bootstrap" + } + ], + "peerDependencies": { + "@popperjs/core": "^2.11.8" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.22.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.2.tgz", + "integrity": "sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001565", + "electron-to-chromium": "^1.4.601", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/btoa": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz", + "integrity": "sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==", + "bin": { + "btoa": "bin/btoa.js" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase-keys": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", + "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "map-obj": "^4.0.0", + "quick-lru": "^4.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001571", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001571.tgz", + "integrity": "sha512-tYq/6MoXhdezDLFZuCO/TKboTzuQ/xR5cFdgXPfDtM7/kchBO3b4VWghE/OAi/DV7tTdhmLjZiZBZi1fA/GheQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/canvg": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/canvg/-/canvg-3.0.10.tgz", + "integrity": "sha512-qwR2FRNO9NlzTeKIPIKpnTY6fqwuYSequ8Ru8c0YkYU7U0oW+hLUvWadLvAu1Rl72OMNiFhoLu4f8eUjQ7l/+Q==", + "optional": true, + "dependencies": { + "@babel/runtime": "^7.12.5", + "@types/raf": "^3.4.0", + "core-js": "^3.8.3", + "raf": "^3.4.1", + "regenerator-runtime": "^0.13.7", + "rgbcolor": "^1.0.1", + "stackblur-canvas": "^2.0.0", + "svg-pathdata": "^6.0.3" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/canvg/node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "optional": true + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "dev": true, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/copy-anything": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", + "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", + "dev": true, + "dependencies": { + "is-what": "^3.14.1" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/core-js": { + "version": "3.34.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.34.0.tgz", + "integrity": "sha512-aDdvlDder8QmY91H88GzNi9EtQi2TjvQhpCX6B1v/dAZHU1AuLgHvRh54RiOerpEhEW46Tkf+vgAViB/CWC0ag==", + "hasInstallScript": true, + "optional": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-compat": { + "version": "3.34.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.34.0.tgz", + "integrity": "sha512-4ZIyeNbW/Cn1wkMMDy+mvrRUxrwFNjKwbhCfQpDd+eLgYipDqp8oGFGtLmhh18EDPKA0g3VUBYOxQGGwvWLVpA==", + "dev": true, + "dependencies": { + "browserslist": "^4.22.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-line-break": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz", + "integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==", + "devOptional": true, + "dependencies": { + "utrie": "^1.0.2" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "dev": true + }, + "node_modules/d3": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/d3/-/d3-7.8.5.tgz", + "integrity": "sha512-JgoahDG51ncUfJu6wX/1vWQEqOflgXyl4MaHqlcSruTez7yhaRKR9i8VjjcQGeS2en/jnFivXuaIMnseMMt0XA==", + "dependencies": { + "d3-array": "3", + "d3-axis": "3", + "d3-brush": "3", + "d3-chord": "3", + "d3-color": "3", + "d3-contour": "4", + "d3-delaunay": "6", + "d3-dispatch": "3", + "d3-drag": "3", + "d3-dsv": "3", + "d3-ease": "3", + "d3-fetch": "3", + "d3-force": "3", + "d3-format": "3", + "d3-geo": "3", + "d3-hierarchy": "3", + "d3-interpolate": "3", + "d3-path": "3", + "d3-polygon": "3", + "d3-quadtree": "3", + "d3-random": "3", + "d3-scale": "4", + "d3-scale-chromatic": "3", + "d3-selection": "3", + "d3-shape": "3", + "d3-time": "3", + "d3-time-format": "4", + "d3-timer": "3", + "d3-transition": "3", + "d3-zoom": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-axis": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz", + "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-brush": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", + "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "3", + "d3-transition": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-chord": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz", + "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==", + "dependencies": { + "d3-path": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-contour": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.2.tgz", + "integrity": "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==", + "dependencies": { + "d3-array": "^3.2.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", + "dependencies": { + "delaunator": "5" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-drag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", + "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-selection": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dsv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", + "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", + "dependencies": { + "commander": "7", + "iconv-lite": "0.6", + "rw": "1" + }, + "bin": { + "csv2json": "bin/dsv2json.js", + "csv2tsv": "bin/dsv2dsv.js", + "dsv2dsv": "bin/dsv2dsv.js", + "dsv2json": "bin/dsv2json.js", + "json2csv": "bin/json2dsv.js", + "json2dsv": "bin/json2dsv.js", + "json2tsv": "bin/json2dsv.js", + "tsv2csv": "bin/dsv2dsv.js", + "tsv2json": "bin/dsv2json.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dsv/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "engines": { + "node": ">= 10" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz", + "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", + "dependencies": { + "d3-dsv": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-force": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", + "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-quadtree": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-geo": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.0.tgz", + "integrity": "sha512-JEo5HxXDdDYXCaWdwLRt79y7giK8SbhZJbFWXqbRTolCHFI5jRqteLzCsq51NKbUoX0PjBVSohxrx+NoOUujYA==", + "dependencies": { + "d3-array": "2.5.0 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-hierarchy": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", + "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-polygon": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz", + "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-quadtree": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", + "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-random": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz", + "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale-chromatic": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz", + "integrity": "sha512-Lx9thtxAKrO2Pq6OO2Ua474opeziKr279P/TKZsMAhYyNDD3EnCffdbgeSYN5O7m2ByQsxtuP2CSDczNUIZ22g==", + "dependencies": { + "d3-color": "1 - 3", + "d3-interpolate": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "dependencies": { + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "d3-selection": "2 - 3" + } + }, + "node_modules/d3-zoom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", + "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "2 - 3", + "d3-transition": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decamelize-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz", + "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==", + "dev": true, + "dependencies": { + "decamelize": "^1.1.0", + "map-obj": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decamelize-keys/node_modules/map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/delaunator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.0.tgz", + "integrity": "sha512-AyLvtyJdbv/U1GkiS6gUUzclRoAY4Gs75qkMygJJhU75LW4DNuSF2RMzpxs9jw9Oz1BobHjTdkG3zdP55VxAqw==", + "dependencies": { + "robust-predicates": "^3.0.0" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dompurify": { + "version": "2.4.7", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.4.7.tgz", + "integrity": "sha512-kxxKlPEDa6Nc5WJi+qRgPbOAbgTpSULL+vI3NUXsZMlkJxTqYI9wg5ZTay2sFrdZRWHPWNi+EdAhcJf81WtoMQ==", + "optional": true + }, + "node_modules/electron-to-chromium": { + "version": "1.4.616", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.616.tgz", + "integrity": "sha512-1n7zWYh8eS0L9Uy+GskE0lkBUNK83cXTVJI0pU3mGprFsbfSdAc15VTFbo+A+Bq4pwstmL30AVcEU3Fo463lNg==", + "dev": true + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/enhanced-resolve": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", + "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/envinfo": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.11.0.tgz", + "integrity": "sha512-G9/6xF1FPbIw0TtalAMaVPpiq2aDEuKLXM314jPVAO9r2fo2a4BLqMNkmRS7O/xPPZ+COAhGIz3ETvHEV3eUcg==", + "dev": true, + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/errno": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", + "dev": true, + "optional": true, + "dependencies": { + "prr": "~1.0.1" + }, + "bin": { + "errno": "cli.js" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-module-lexer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.4.1.tgz", + "integrity": "sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==", + "dev": true + }, + "node_modules/esbuild": { + "version": "0.19.10", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.10.tgz", + "integrity": "sha512-S1Y27QGt/snkNYrRcswgRFqZjaTG5a5xM3EQo97uNBnH505pdzSNe/HLBq1v0RO7iK/ngdbhJB6mDAp0OK+iUA==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.19.10", + "@esbuild/android-arm": "0.19.10", + "@esbuild/android-arm64": "0.19.10", + "@esbuild/android-x64": "0.19.10", + "@esbuild/darwin-arm64": "0.19.10", + "@esbuild/darwin-x64": "0.19.10", + "@esbuild/freebsd-arm64": "0.19.10", + "@esbuild/freebsd-x64": "0.19.10", + "@esbuild/linux-arm": "0.19.10", + "@esbuild/linux-arm64": "0.19.10", + "@esbuild/linux-ia32": "0.19.10", + "@esbuild/linux-loong64": "0.19.10", + "@esbuild/linux-mips64el": "0.19.10", + "@esbuild/linux-ppc64": "0.19.10", + "@esbuild/linux-riscv64": "0.19.10", + "@esbuild/linux-s390x": "0.19.10", + "@esbuild/linux-x64": "0.19.10", + "@esbuild/netbsd-x64": "0.19.10", + "@esbuild/openbsd-x64": "0.19.10", + "@esbuild/sunos-x64": "0.19.10", + "@esbuild/win32-arm64": "0.19.10", + "@esbuild/win32-ia32": "0.19.10", + "@esbuild/win32-x64": "0.19.10" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eslint": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz", + "integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.56.0", + "@humanwhocodes/config-array": "^0.11.13", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-formatter-pretty": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eslint-formatter-pretty/-/eslint-formatter-pretty-4.1.0.tgz", + "integrity": "sha512-IsUTtGxF1hrH6lMWiSl1WbGaiP01eT6kzywdY1U+zLc0MP+nwEnUiS9UI8IaOTUhTeQJLlCEWIbXINBH4YJbBQ==", + "dev": true, + "dependencies": { + "@types/eslint": "^7.2.13", + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.0", + "eslint-rule-docs": "^1.1.5", + "log-symbols": "^4.0.0", + "plur": "^4.0.0", + "string-width": "^4.2.0", + "supports-hyperlinks": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-formatter-pretty/node_modules/@types/eslint": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.29.0.tgz", + "integrity": "sha512-VNcvioYDH8/FxaeTKkM4/TiTwt6pBV9E3OfGmvaw8tPl0rrHCJ4Ll15HRT+pMiFAf/MLQvAzC+6RzUMEL9Ceng==", + "dev": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/eslint-formatter-pretty/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/eslint-formatter-pretty/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint-formatter-pretty/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/eslint-formatter-pretty/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/eslint-formatter-pretty/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint-formatter-pretty/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", + "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", + "dev": true, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/eslint-plugin-react-refresh": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.5.tgz", + "integrity": "sha512-D53FYKJa+fDmZMtriODxvhwrO+IOqrxoEo21gMA0sjHdU6dPVH4OhyFip9ypl8HOF5RV5KdTo+rBQLvnY2cO8w==", + "dev": true, + "peerDependencies": { + "eslint": ">=7" + } + }, + "node_modules/eslint-rule-docs": { + "version": "1.1.235", + "resolved": "https://registry.npmjs.org/eslint-rule-docs/-/eslint-rule-docs-1.1.235.tgz", + "integrity": "sha512-+TQ+x4JdTnDoFEXXb3fDvfGOwnyNV7duH8fXWTPD1ieaBmB8omj7Gw/pMBBu4uI2uJCCU8APDaQJzWuXnTsH4A==", + "dev": true + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/eslint/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/eslint/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true, + "engines": { + "node": ">= 4.9.1" + } + }, + "node_modules/fastq": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.16.0.tgz", + "integrity": "sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fflate": { + "version": "0.4.8", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.4.8.tgz", + "integrity": "sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA==" + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.9", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", + "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", + "dev": true + }, + "node_modules/follow-redirects": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", + "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/font-awesome": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/font-awesome/-/font-awesome-4.7.0.tgz", + "integrity": "sha512-U6kGnykA/6bFmg1M/oT9EkFeIYv7JlX3bozwQJWiiLz6L0w3F5vBVPxHlwyX/vtNq1ckcpRKOB9f2Qal/VtFpg==", + "engines": { + "node": ">=0.10.3" + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "node_modules/hard-rejection": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", + "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/hosted-git-info/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/html2canvas": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz", + "integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==", + "devOptional": true, + "dependencies": { + "css-line-break": "^2.1.0", + "text-segmentation": "^1.0.3" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", + "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/image-size": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", + "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==", + "dev": true, + "optional": true, + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "engines": { + "node": ">=12" + } + }, + "node_modules/interpret": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz", + "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/ionicons": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/ionicons/-/ionicons-7.2.2.tgz", + "integrity": "sha512-I3iYIfc9Q9FRifWyFSwTAvbEABWlWY32i0sAVDDPGYnaIZVugkLCZFbEcrphW6ixVPg8tt1oLwalo/JJwbEqnA==", + "dev": true, + "dependencies": { + "@stencil/core": "^4.0.3" + } + }, + "node_modules/irregular-plurals": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/irregular-plurals/-/irregular-plurals-3.5.0.tgz", + "integrity": "sha512-1ANGLZ+Nkv1ptFb2pa8oG8Lem4krflKuX/gINiHJHjJUKaJHk/SXk5x6K3J+39/p0h1RQ2saROclJJ+QLvETCQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-what": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", + "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==", + "dev": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-diff/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-diff/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-diff/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-diff/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-diff/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-diff/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jest-worker/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/jquery": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz", + "integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==", + "dev": true + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jspdf": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/jspdf/-/jspdf-2.5.1.tgz", + "integrity": "sha512-hXObxz7ZqoyhxET78+XR34Xu2qFGrJJ2I2bE5w4SM8eFaFEkW2xcGRVUss360fYelwRSid/jT078kbNvmoW0QA==", + "dependencies": { + "@babel/runtime": "^7.14.0", + "atob": "^2.1.2", + "btoa": "^1.2.1", + "fflate": "^0.4.8" + }, + "optionalDependencies": { + "canvg": "^3.0.6", + "core-js": "^3.6.0", + "dompurify": "^2.2.0", + "html2canvas": "^1.0.0-rc.5" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/less": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/less/-/less-3.13.1.tgz", + "integrity": "sha512-SwA1aQXGUvp+P5XdZslUOhhLnClSLIjWvJhmd+Vgib5BFIr9lMNlQwmwUNOjXThF/A0x+MCYYPeWEfeWiLRnTw==", + "dev": true, + "dependencies": { + "copy-anything": "^2.0.1", + "tslib": "^1.10.0" + }, + "bin": { + "lessc": "bin/lessc" + }, + "engines": { + "node": ">=6" + }, + "optionalDependencies": { + "errno": "^0.1.1", + "graceful-fs": "^4.1.2", + "image-size": "~0.5.0", + "make-dir": "^2.1.0", + "mime": "^1.4.1", + "native-request": "^1.0.5", + "source-map": "~0.6.0" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true, + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/log-symbols/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/log-symbols/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/log-symbols/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "optional": true, + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "optional": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/map-obj": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", + "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/meow": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-9.0.0.tgz", + "integrity": "sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ==", + "dev": true, + "dependencies": { + "@types/minimist": "^1.2.0", + "camelcase-keys": "^6.2.2", + "decamelize": "^1.2.0", + "decamelize-keys": "^1.1.0", + "hard-rejection": "^2.1.0", + "minimist-options": "4.1.0", + "normalize-package-data": "^3.0.0", + "read-pkg-up": "^7.0.1", + "redent": "^3.0.0", + "trim-newlines": "^3.0.0", + "type-fest": "^0.18.0", + "yargs-parser": "^20.2.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/meow/node_modules/type-fest": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", + "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "optional": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist-options": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", + "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", + "dev": true, + "dependencies": { + "arrify": "^1.0.1", + "is-plain-obj": "^1.1.0", + "kind-of": "^6.0.3" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/mobx": { + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/mobx/-/mobx-6.12.0.tgz", + "integrity": "sha512-Mn6CN6meXEnMa0a5u6a5+RKrqRedHBhZGd15AWLk9O6uFY4KYHzImdt8JI8WODo1bjTSRnwXhJox+FCUZhCKCQ==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mobx" + } + }, + "node_modules/mobx-react": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/mobx-react/-/mobx-react-9.1.0.tgz", + "integrity": "sha512-DeDRTYw4AlgHw8xEXtiZdKKEnp+c5/jeUgTbTQXEqnAzfkrgYRWP3p3Nv3Whc2CEcM/mDycbDWGjxKokQdlffg==", + "dev": true, + "dependencies": { + "mobx-react-lite": "^4.0.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mobx" + }, + "peerDependencies": { + "mobx": "^6.9.0", + "react": "^16.8.0 || ^17 || ^18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, + "node_modules/mobx-react-lite": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/mobx-react-lite/-/mobx-react-lite-4.0.5.tgz", + "integrity": "sha512-StfB2wxE8imKj1f6T8WWPf4lVMx3cYH9Iy60bbKXEs21+HQ4tvvfIBZfSmMXgQAefi8xYEwQIz4GN9s0d2h7dg==", + "dev": true, + "dependencies": { + "use-sync-external-store": "^1.2.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mobx" + }, + "peerDependencies": { + "mobx": "^6.9.0", + "react": "^16.8.0 || ^17 || ^18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/native-request": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/native-request/-/native-request-1.1.0.tgz", + "integrity": "sha512-uZ5rQaeRn15XmpgE0xoPL8YWqcX90VtCFglYwAgkvKM5e8fog+vePLAhHxuuv/gRkrQxIeh5U3q9sMNUrENqWw==", + "dev": true, + "optional": true + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "dev": true + }, + "node_modules/normalize-package-data": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", + "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^4.0.1", + "is-core-module": "^2.5.0", + "semver": "^7.3.4", + "validate-npm-package-license": "^3.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pace-progress": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pace-progress/-/pace-progress-1.0.2.tgz", + "integrity": "sha512-uhOU/vb2N6TM8gkoEGOLusLVghxJ+P1OtundjeoVzUhspa58JZ64YLsLJZVK8JU9utDeuHr6Xz/cXxdX3rWmtg==", + "deprecated": "Disclaimer, We no longer use this library internally and are focusing our efforts on open sourcing and maintaining projects that we do use and can meaningfully contribute to. Sorry for any frustrations with this project (we're happy to link to any fork that has an excited, commited maintainer)." + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/perfect-scrollbar": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/perfect-scrollbar/-/perfect-scrollbar-1.5.5.tgz", + "integrity": "sha512-dzalfutyP3e/FOpdlhVryN4AJ5XDVauVWxybSkLZmakFE2sS3y3pc4JnSprw8tGmHvkaG5Edr5T7LBTZ+WWU2g==", + "dev": true + }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", + "optional": true + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/plur": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/plur/-/plur-4.0.0.tgz", + "integrity": "sha512-4UGewrYgqDFw9vV6zNV+ADmPAUAfJPKtGvb/VdpQAx25X5f3xXdGdyOEVFwkl8Hl/tl7+xbeHqSEM+D5/TirUg==", + "dev": true, + "dependencies": { + "irregular-plurals": "^3.2.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/popper.js": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz", + "integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==", + "deprecated": "You can find the new Popper v2 at @popperjs/core, this package is dedicated to the legacy v1", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/postcss": { + "version": "8.4.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.32.tgz", + "integrity": "sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-combine-duplicated-selectors": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/postcss-combine-duplicated-selectors/-/postcss-combine-duplicated-selectors-10.0.3.tgz", + "integrity": "sha512-IP0BmwFloCskv7DV7xqvzDXqMHpwdczJa6ZvIW8abgHdcIHs9mCJX2ltFhu3EwA51ozp13DByng30+Ke+eIExA==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^10.0.0 || ^12.0.0 || >=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz", + "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true + }, + "node_modules/prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", + "dev": true, + "optional": true + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/quick-lru": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", + "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/raf": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", + "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", + "optional": true, + "dependencies": { + "performance-now": "^2.1.0" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", + "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" + }, + "peerDependencies": { + "react": "^18.2.0" + } + }, + "node_modules/react-dom-factories": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/react-dom-factories/-/react-dom-factories-1.0.2.tgz", + "integrity": "sha512-Bmic2N3oKji7vw9qjDr2dmwHvOATbFSnKy7EH0uT/qjvzIUsiXp6Yquk72LJ3WfMtRnq3ujXMMo7GsJeLPfFWw==" + }, + "node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, + "node_modules/react-refresh": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz", + "integrity": "sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-router": { + "version": "6.21.1", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.21.1.tgz", + "integrity": "sha512-W0l13YlMTm1YrpVIOpjCADJqEUpz1vm+CMo47RuFX4Ftegwm6KOYsL5G3eiE52jnJpKvzm6uB/vTKTPKM8dmkA==", + "dependencies": { + "@remix-run/router": "1.14.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8" + } + }, + "node_modules/react-router-dom": { + "version": "6.21.1", + "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.21.1.tgz", + "integrity": "sha512-QCNrtjtDPwHDO+AO21MJd7yIcr41UetYt5jzaB9Y1UYaPTCnVuJq6S748g1dE11OQlCFIQg+RtAA1SEZIyiBeA==", + "dependencies": { + "@remix-run/router": "1.14.1", + "react-router": "6.21.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "react": ">=16.8", + "react-dom": ">=16.8" + } + }, + "node_modules/read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "dependencies": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "dev": true, + "dependencies": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg-up/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg-up/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg/node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "node_modules/read-pkg/node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/read-pkg/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/read-pkg/node_modules/type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/rechoir": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", + "dev": true, + "dependencies": { + "resolve": "^1.20.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", + "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + }, + "node_modules/regenerator-transform": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, + "node_modules/regexpu-core": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", + "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", + "dev": true, + "dependencies": { + "@babel/regjsgen": "^0.8.0", + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "dev": true, + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-cwd/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rgbcolor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/rgbcolor/-/rgbcolor-1.0.1.tgz", + "integrity": "sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==", + "optional": true, + "engines": { + "node": ">= 0.8.15" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/robust-predicates": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", + "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==" + }, + "node_modules/rollup": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.9.1.tgz", + "integrity": "sha512-pgPO9DWzLoW/vIhlSoDByCzcpX92bKEorbgXuZrqxByte3JFk2xSW2JEeAcyLc9Ru9pqcNNW+Ob7ntsk2oT/Xw==", + "dev": true, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.9.1", + "@rollup/rollup-android-arm64": "4.9.1", + "@rollup/rollup-darwin-arm64": "4.9.1", + "@rollup/rollup-darwin-x64": "4.9.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.9.1", + "@rollup/rollup-linux-arm64-gnu": "4.9.1", + "@rollup/rollup-linux-arm64-musl": "4.9.1", + "@rollup/rollup-linux-riscv64-gnu": "4.9.1", + "@rollup/rollup-linux-x64-gnu": "4.9.1", + "@rollup/rollup-linux-x64-musl": "4.9.1", + "@rollup/rollup-win32-arm64-msvc": "4.9.1", + "@rollup/rollup-win32-ia32-msvc": "4.9.1", + "@rollup/rollup-win32-x64-msvc": "4.9.1", + "fsevents": "~2.3.2" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==" + }, + "node_modules/saas": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/saas/-/saas-1.0.0.tgz", + "integrity": "sha512-FgayhFS18BlPfcyMcOqxD7PIyNyUjqyv8R+rsr3X2KRK2icEUL4uvWBF+lZ0IPqJIO2kUO0d20OXY+R+pdriqg==", + "dev": true + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/schema-utils/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/schema-utils/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/schema-utils/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/serialize-javascript": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", + "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/simple-line-icons": { + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/simple-line-icons/-/simple-line-icons-2.5.5.tgz", + "integrity": "sha512-v52iGG/qFZTSD/70yOfA1lYoN6zmjEfDjzFT6U6jNSCsh/aeVjy+8sYyTXWz1w7tLIkN2XeMmG+cLJp/0zYK4Q==", + "dev": true, + "dependencies": { + "less": "^3.12.2" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.16", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.16.tgz", + "integrity": "sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==", + "dev": true + }, + "node_modules/stackblur-canvas": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/stackblur-canvas/-/stackblur-canvas-2.6.0.tgz", + "integrity": "sha512-8S1aIA+UoF6erJYnglGPug6MaHYGo1Ot7h5fuXx4fUPvcvQfcdw2o/ppCse63+eZf8PPidSu4v1JnmEVtEDnpg==", + "optional": true, + "engines": { + "node": ">=0.1.14" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-hyperlinks": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz", + "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-hyperlinks/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-hyperlinks/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/svg-pathdata": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/svg-pathdata/-/svg-pathdata-6.0.3.tgz", + "integrity": "sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==", + "optional": true, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/terser": { + "version": "5.26.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.26.0.tgz", + "integrity": "sha512-dytTGoE2oHgbNV9nTzgBEPaqAWvcJNl66VZ0BkJqlvp71IjO8CxdBx/ykCNb47cLnCmCvRZ6ZR0tLkqvZCdVBQ==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.9", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.9.tgz", + "integrity": "sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.17", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.16.8" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/text-segmentation": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz", + "integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==", + "devOptional": true, + "dependencies": { + "utrie": "^1.0.2" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/trim-newlines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", + "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ts-api-utils": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", + "integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==", + "dev": true, + "engines": { + "node": ">=16.13.0" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/ts-loader": { + "version": "9.5.1", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.1.tgz", + "integrity": "sha512-rNH3sK9kGZcH9dYzC7CewQm4NtxJTjSEVRJ2DyBZR7f8/wcta+iV44UPCXc5+nzDzivKtlzV6c9P4e+oFhDLYg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "enhanced-resolve": "^5.0.0", + "micromatch": "^4.0.0", + "semver": "^7.3.4", + "source-map": "^0.7.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "typescript": "*", + "webpack": "^5.0.0" + } + }, + "node_modules/ts-loader/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ts-loader/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/ts-loader/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/ts-loader/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/ts-loader/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ts-loader/node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/ts-loader/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tsd": { + "version": "0.30.0", + "resolved": "https://registry.npmjs.org/tsd/-/tsd-0.30.0.tgz", + "integrity": "sha512-aHL4rEuf3wwRzKCH8yqsE1oMAJYn7SAQ2JfWSgjr1e5/fqr+ggohQazECMpSoRAqSQeM/iIFugoyL/0eFwdTcA==", + "dev": true, + "dependencies": { + "@tsd/typescript": "~5.3.3", + "eslint-formatter-pretty": "^4.1.0", + "globby": "^11.0.1", + "jest-diff": "^29.0.3", + "meow": "^9.0.0", + "path-exists": "^4.0.0", + "read-pkg-up": "^7.0.0" + }, + "bin": { + "tsd": "dist/cli.js" + }, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", + "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/use-sync-external-store": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", + "dev": true, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/utrie": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz", + "integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==", + "devOptional": true, + "dependencies": { + "base64-arraybuffer": "^1.0.2" + } + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/vite": { + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.0.10.tgz", + "integrity": "sha512-2P8J7WWgmc355HUMlFrwofacvr98DAjoE52BfdbwQtyLH06XKwaL/FMnmKM2crF0iX4MpmMKoDlNCB1ok7zHCw==", + "dev": true, + "dependencies": { + "esbuild": "^0.19.3", + "postcss": "^8.4.32", + "rollup": "^4.2.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "dev": true, + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack": { + "version": "5.89.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.89.0.tgz", + "integrity": "sha512-qyfIC10pOr70V+jkmud8tMfajraGCZMBWJtrmuBymQKCrLTRejBI8STDp1MCyZu/QTdZSeacCQYpYNQVOzX5kw==", + "dev": true, + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^1.0.0", + "@webassemblyjs/ast": "^1.11.5", + "@webassemblyjs/wasm-edit": "^1.11.5", + "@webassemblyjs/wasm-parser": "^1.11.5", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.9.0", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.15.0", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.7", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-cli": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz", + "integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==", + "dev": true, + "dependencies": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^2.1.1", + "@webpack-cli/info": "^2.0.2", + "@webpack-cli/serve": "^2.0.5", + "colorette": "^2.0.14", + "commander": "^10.0.1", + "cross-spawn": "^7.0.3", + "envinfo": "^7.7.3", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^3.1.1", + "rechoir": "^0.8.0", + "webpack-merge": "^5.7.3" + }, + "bin": { + "webpack-cli": "bin/cli.js" + }, + "engines": { + "node": ">=14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "5.x.x" + }, + "peerDependenciesMeta": { + "@webpack-cli/generators": { + "optional": true + }, + "webpack-bundle-analyzer": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/webpack-cli/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "dev": true, + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/webpack/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", + "dev": true + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/src/GoodBooksReact/package.json b/src/GoodBooksReact/package.json new file mode 100644 index 000000000..d6dbe41c0 --- /dev/null +++ b/src/GoodBooksReact/package.json @@ -0,0 +1,66 @@ +{ + "name": "goodbooksreact", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "webpack": "webpack", + "gulp": "gulp", + "tsc": "tsc", + "dev": "vite", + "build": "tsc && vite build", + "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", + "preview": "vite preview" + }, + "dependencies": { + "accounting": "^0.4.1", + "ag-grid": "^18.1.2", + "d3": "^7.8.5", + "font-awesome": "^4.7.0", + "jspdf": "^2.5.1", + "pace-progress": "^1.0.2", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-dom-factories": "^1.0.2", + "react-router": "^6.21.1", + "react-router-dom": "^6.21.1" + }, + "devDependencies": { + "@babel/core": "^7.23.6", + "@babel/plugin-proposal-decorators": "^7.23.6", + "@babel/plugin-syntax-decorators": "^7.23.3", + "@babel/preset-env": "^7.23.6", + "@coreui/coreui": "^4.3.2", + "@coreui/icons": "^3.0.1", + "@types/accounting": "^0.4.5", + "@types/react": "^18.2.43", + "@types/react-dom": "^18.2.17", + "@types/react-router": "^5.1.20", + "@types/react-router-dom": "^5.3.3", + "@typescript-eslint/eslint-plugin": "^6.14.0", + "@typescript-eslint/parser": "^6.14.0", + "@vitejs/plugin-react": "^4.2.1", + "ag-grid-community": "^31.0.1", + "ajv": "^8.12.0", + "axios": "^1.6.2", + "bootstrap": "^5.3.2", + "eslint": "^8.55.0", + "eslint-plugin-react-hooks": "^4.6.0", + "eslint-plugin-react-refresh": "^0.4.5", + "html2canvas": "^1.4.1", + "ionicons": "^7.2.2", + "jquery": "^3.7.1", + "mobx": "^6.12.0", + "mobx-react": "^9.1.0", + "perfect-scrollbar": "^1.5.5", + "popper.js": "^1.16.1", + "saas": "^1.0.0", + "simple-line-icons": "^2.5.5", + "ts-loader": "^9.5.1", + "tsd": "^0.30.0", + "typescript": "^5.2.2", + "vite": "^5.0.8", + "webpack": "^5.89.0", + "webpack-cli": "^5.1.4" + } +} diff --git a/src/GoodBooksReact/public/staticwebapp.config.json b/src/GoodBooksReact/public/staticwebapp.config.json new file mode 100644 index 000000000..0bbb59398 --- /dev/null +++ b/src/GoodBooksReact/public/staticwebapp.config.json @@ -0,0 +1,9 @@ +{ + "navigationFallback": { + "rewrite": "index.html", + "exclude": ["/static/media/*.{png,jpg,jpeg,gif,bmp}", "/static/css/*"] + }, + "mimeTypes": { + ".json": "text/json" + } +} \ No newline at end of file diff --git a/src/GoodBooksReact/public/vite.svg b/src/GoodBooksReact/public/vite.svg new file mode 100644 index 000000000..e7b8dfb1b --- /dev/null +++ b/src/GoodBooksReact/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/GoodBooksReact/src/App.tsx b/src/GoodBooksReact/src/App.tsx new file mode 100644 index 000000000..c7b3e0f8f --- /dev/null +++ b/src/GoodBooksReact/src/App.tsx @@ -0,0 +1,21 @@ +// import Heading from "./components/Heading" +// import Section from "./components/Section" +// import Counter from "./components/Counter" +// import List from "./components/List" +// import Home from "./components/Home/Index" +import { Outlet } from "react-router" +import Home from "./components/Home/Index" + +// https://www.youtube.com/watch?v=G7UzhrNX60o + +function App() { + + return ( + <> + + + + ) +} + +export default App diff --git a/src/GoodBooksReact/src/assets/react.svg b/src/GoodBooksReact/src/assets/react.svg new file mode 100644 index 000000000..6c87de9bb --- /dev/null +++ b/src/GoodBooksReact/src/assets/react.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/GoodBooksReact/src/components/Counter.tsx b/src/GoodBooksReact/src/components/Counter.tsx new file mode 100644 index 000000000..ba835722f --- /dev/null +++ b/src/GoodBooksReact/src/components/Counter.tsx @@ -0,0 +1,15 @@ +import { useState } from "react" + +const Counter = () => { + const [count, setCount] = useState(1) + return( + <> +

    Count is {count}

    + +      + + + ) +} + +export default Counter diff --git a/src/AccountGoWeb/Scripts/Financials/JournalEntry.tsx b/src/GoodBooksReact/src/components/Financials/JournalEntry.tsx similarity index 73% rename from src/AccountGoWeb/Scripts/Financials/JournalEntry.tsx rename to src/GoodBooksReact/src/components/Financials/JournalEntry.tsx index 50118e226..ff9a6248c 100644 --- a/src/AccountGoWeb/Scripts/Financials/JournalEntry.tsx +++ b/src/GoodBooksReact/src/components/Financials/JournalEntry.tsx @@ -1,25 +1,21 @@ import * as React from "react"; -import * as ReactDOM from "react-dom"; +//import * as ReactDOM from "react-dom"; import {observer} from "mobx-react"; -import {autorun, reaction, toJS, intercept} from 'mobx'; -import * as d3 from "d3"; import SelectVoucherType from "../Shared/Components/SelectVoucherType"; import SelectAccount from "../Shared/Components/SelectAccount"; import SelectDebitCredit from "../Shared/Components/SelectDebitCredit"; import JournalEntryStore from "../Shared/Stores/Financials/JournalEntryStore"; -import JournalEntryUIStore from "../Shared/Stores/Financials/JournalEntryUIStore"; -let store = new JournalEntryStore(); -let uiStore = new JournalEntryUIStore(store); +const store = new JournalEntryStore(); -@observer -class ValidationErrors extends React.Component{ +class ValidationErrors extends React.Component { render() { if (store.validationErrors !== undefined && store.validationErrors.length > 0) { - var errors = []; - store.validationErrors.map(function (item, index) { + const errors: string[] = []; + store.validationErrors.map(function (item: any, index: number) { + const errors: React.ReactNode[] = []; errors.push(
  • {item}
  • ); }); return ( @@ -33,15 +29,15 @@ class ValidationErrors extends React.Component{ return null; } } +const ObservedValidationErrors = observer(ValidationErrors); -@observer -class EditButton extends React.Component{ +class EditButton extends React.Component { onClickEditButton() { // Remove " disabledControl" from current className - var nodes = document.getElementById("divJournalEntryForm").getElementsByTagName('*'); - for (var i = 0; i < nodes.length; i++) { - var subStringLength = nodes[i].className.length - " disabledControl".length; - nodes[i].className = nodes[i].className.substring(0, subStringLength); + const nodes = document.getElementById("divJournalEntryForm")?.getElementsByTagName('*'); + for (let i = 0; i < nodes!.length; i++) { + const subStringLength = nodes![i].className.length - " disabledControl".length; + nodes![i].className = nodes![i].className.substring(0, subStringLength); } store.changedEditMode(true) } @@ -57,10 +53,10 @@ class EditButton extends React.Component{ ); } } +const ObservedEditButton = observer(EditButton); -@observer -class SaveJournalEntryButton extends React.Component{ - onClickSaveNewJournalEntry(e) { +class SaveJournalEntryButton extends React.Component { + onClickSaveNewJournalEntry() { store.saveNewJournalEntry(); } render() { @@ -73,10 +69,11 @@ class SaveJournalEntryButton extends React.Component{ ); } } +const ObservedSaveJournalEntryButton = observer(SaveJournalEntryButton); -class CancelJournalEntryButton extends React.Component{ +class CancelJournalEntryButton extends React.Component { cancelOnClick() { - let baseUrl = location.protocol + const baseUrl = location.protocol + "//" + location.hostname + (location.port && ":" + location.port) + "/"; @@ -92,9 +89,8 @@ class CancelJournalEntryButton extends React.Component{ } } -@observer -class PostJournalEntryButton extends React.Component{ - postOnClick(e) { +class PostJournalEntryButton extends React.Component { + postOnClick() { store.postJournal(); } @@ -107,33 +103,34 @@ class PostJournalEntryButton extends React.Component{ ); } } +const ObservedPostJournalEntryButton = observer(PostJournalEntryButton); -@observer -class JournalEntryHeader extends React.Component{ - onChangeJournalDate(e) { - store.changedJournalDate(e.target.value); +class JournalEntryHeader extends React.Component { + onChangeJournalDate(e: React.ChangeEvent) { + const dateValue = new Date(e.target.value); + store.changedJournalDate(dateValue); } - onChangeReferenceNo(e) { + onChangeReferenceNo(e: React.ChangeEvent) { store.changedReferenceNo(e.target.value); } - onChangeMemo(e) { + onChangeMemo(e: React.ChangeEvent) { store.changedMemo(e.target.value); } render() { return (
    -
    - General +
    + General
    Date
    + value={store.journalEntry.journalDate !== undefined ? store.journalEntry.journalDate.toISOString().substring(0, 10) : new Date(Date.now()).toISOString().substring(0, 10) } />
    Voucher
    @@ -159,33 +156,36 @@ class JournalEntryHeader extends React.Component{ ); } } +const ObservedJournalEntryHeader = observer(JournalEntryHeader); + +class JournalEntryLines extends React.Component { -@observer -class JournalEntryLines extends React.Component{ - onChangeAmount(e) { + onChangeAmount(e: any) { store.updateLineItem(e.target.name, "amount", e.target.value); } - onChangeMemo(e) { + + onChangeMemo(e: any) { store.updateLineItem(e.target.name, "memo", e.target.value); } - onClickRemoveLineItem(i, e) { + + onClickRemoveLineItem(i: number) { store.removeLineItem(i); } + addLineItem() { - var accountId, drcr, amount, memo; - accountId = (document.getElementById("optNewAccountId") as HTMLInputElement).value;; - drcr = (document.getElementById("optNewDebitCredit") as HTMLInputElement).value; - amount = (document.getElementById("txtNewAmount") as HTMLInputElement).value; - memo = (document.getElementById("txtNewMemo") as HTMLInputElement).value; + const accountId: string = (document.getElementById("optNewAccountId") as HTMLInputElement).value; + const drcr: string = (document.getElementById("optNewDebitCredit") as HTMLInputElement).value; + const amount: string = (document.getElementById("txtNewAmount") as HTMLInputElement).value; + const memo: string = (document.getElementById("txtNewMemo") as HTMLInputElement).value; - store.addLineItem(0, accountId, drcr, amount, memo); + store.addLineItem(0, Number(accountId), Number(drcr), Number(amount), memo); (document.getElementById("txtNewAmount") as HTMLInputElement).value = "0"; (document.getElementById("txtNewMemo") as HTMLInputElement).value = ""; } render() { - var lineItems = []; - for (var i = 0; i < store.journalEntry.journalEntryLines.length; i++) { + const lineItems: JSX.Element[] = []; + for (let i = 0; i < store.journalEntry.journalEntryLines.length; i++) { lineItems.push( @@ -236,28 +236,30 @@ class JournalEntryLines extends React.Component{ ); } } +const ObservedJournalEntryLines = observer(JournalEntryLines); -@observer -export default class JournalEntry extends React.Component { +class JournalEntry extends React.Component { render() { return (
    - +
    - - - + + +
    - + - +
    ); } } +const ObservedJournalEntry = observer(JournalEntry); + +export default ObservedJournalEntry; -ReactDOM.render(, document.getElementById("divJournalEntry")); \ No newline at end of file diff --git a/src/GoodBooksReact/src/components/Heading.tsx b/src/GoodBooksReact/src/components/Heading.tsx new file mode 100644 index 000000000..b3e1acadd --- /dev/null +++ b/src/GoodBooksReact/src/components/Heading.tsx @@ -0,0 +1,13 @@ +import { ReactElement } from "react" + +type HeadingProps = {title: string} + +const Heading = ({title}: HeadingProps): ReactElement => { + return( +
    +

    {title}

    +
    + ) +} + +export default Heading diff --git a/src/GoodBooksReact/src/components/Home/Index.tsx b/src/GoodBooksReact/src/components/Home/Index.tsx new file mode 100644 index 000000000..d763afbb2 --- /dev/null +++ b/src/GoodBooksReact/src/components/Home/Index.tsx @@ -0,0 +1,96 @@ +import * as React from "react"; + +type HomeProps = { + // specify the props type here +}; + +type HomeState = { + // specify the state type here +}; + +class Home extends React.Component { + render() { + return ( +
    + +
    + + ); + } +} + +export default Home; \ No newline at end of file diff --git a/src/GoodBooksReact/src/components/List.tsx b/src/GoodBooksReact/src/components/List.tsx new file mode 100644 index 000000000..af52353a1 --- /dev/null +++ b/src/GoodBooksReact/src/components/List.tsx @@ -0,0 +1,22 @@ +import { ReactNode } from "react" + +interface ListProps { + items: T[], + render: (item: T) => ReactNode +} + +const List = ({items, render}: ListProps) => { + return( +
    +
      + {items.map((item, index) => ( +
    • + {render(item)} +
    • + ))} +
    +
    + ) +} + +export default List \ No newline at end of file diff --git a/src/AccountGoWeb/Scripts/Purchasing/PurchaseInvoice.tsx b/src/GoodBooksReact/src/components/Purchasing/PurchaseInvoice.tsx similarity index 72% rename from src/AccountGoWeb/Scripts/Purchasing/PurchaseInvoice.tsx rename to src/GoodBooksReact/src/components/Purchasing/PurchaseInvoice.tsx index a32f93a01..5d7d2a8f1 100644 --- a/src/AccountGoWeb/Scripts/Purchasing/PurchaseInvoice.tsx +++ b/src/GoodBooksReact/src/components/Purchasing/PurchaseInvoice.tsx @@ -1,5 +1,4 @@ import * as React from "react"; -import * as ReactDOM from "react-dom"; import {observer} from "mobx-react"; import * as accounting from "accounting"; @@ -9,23 +8,24 @@ import SelectLineItem from "../Shared/Components/SelectLineItem"; import SelectLineMeasurement from "../Shared/Components/SelectLineMeasurement"; import PurchaseInvoiceStore from "../Shared/Stores/Purchasing/PurchaseInvoiceStore"; +import PurchaseInvoiceLine from "../Shared/Stores/Purchasing/PurchaseInvoiceLine"; -let purchId = window.location.search.split("?purchId=")[1]; -let invoiceId = window.location.search.split("?invoiceId=")[1]; +const purchId = window.location.search.split("?purchId=")[1]; +const invoiceId = window.location.search.split("?invoiceId=")[1]; -let store = new PurchaseInvoiceStore(purchId, invoiceId); +const store = new PurchaseInvoiceStore(Number(purchId), Number(invoiceId)); -let baseUrl = location.protocol - + "//" + location.hostname - + (location.port && ":" + location.port) - + "/"; +// let baseUrl: string = location.protocol +// + "//" + location.hostname +// + (location.port && ":" + location.port) +// + "/"; -@observer -class ValidationErrors extends React.Component{ +class ValidationErrors extends React.Component { render() { if (store.validationErrors !== undefined && store.validationErrors.length > 0) { - var errors = []; + const errors: string[] = []; store.validationErrors.map(function (item, index) { + const errors: React.ReactNode[] = []; errors.push(
  • {item}
  • ); }); return ( @@ -40,15 +40,15 @@ class ValidationErrors extends React.Component{ return null; } } +const ObservedValidationErrors = observer(ValidationErrors); -@observer -class EditButton extends React.Component{ +class EditButton extends React.Component { onClickEditButton() { // Remove " disabledControl" from current className - var nodes = document.getElementById("divPurchaseInvoiceForm").getElementsByTagName('*'); - for (var i = 0; i < nodes.length; i++) { - var subStringLength = nodes[i].className.length - " disabledControl".length; - nodes[i].className = nodes[i].className.substring(0, subStringLength); + const nodes = document.getElementById("divPurchaseInvoiceForm")?.getElementsByTagName('*'); + for (let i = 0; i < nodes!.length; i++) { + const subStringLength = nodes![i].className.length - " disabledControl".length; + nodes![i].className = nodes![i].className.substring(0, subStringLength); } store.changedEditMode(true); } @@ -64,10 +64,10 @@ class EditButton extends React.Component{ ); } } +const ObservedEditButton = observer(EditButton); -@observer -class SavePurchaseInvoiceButton extends React.Component{ - saveNewPurchaseInvoice(e) { +class SavePurchaseInvoiceButton extends React.Component{ + saveNewPurchaseInvoice() { store.savePurchaseInvoice(); } @@ -81,10 +81,11 @@ class SavePurchaseInvoiceButton extends React.Component{ ); } } +const ObservedSavePurchaseInvoiceButton = observer(SavePurchaseInvoiceButton); -class CancelPurchaseInvoiceButton extends React.Component{ +class CancelPurchaseInvoiceButton extends React.Component { cancelOnClick() { - let baseUrl = location.protocol + const baseUrl = location.protocol + "//" + location.hostname + (location.port && ":" + location.port) + "/"; @@ -101,9 +102,8 @@ class CancelPurchaseInvoiceButton extends React.Component{ } } -@observer -class PostButton extends React.Component{ - postOnClick(e) { +class PostButton extends React.Component { + postOnClick() { store.postInvoice(); } @@ -116,23 +116,26 @@ class PostButton extends React.Component{ ); } } +const ObservedPostButton = observer(PostButton); -@observer -class PurchaseInvoiceHeader extends React.Component{ - onChangeInvoiceDate(e) { - store.changedInvoiceDate(e.target.value); +class PurchaseInvoiceHeader extends React.Component { + onChangeInvoiceDate(e: React.ChangeEvent) { + store.changedInvoiceDate(new Date(e.target.value)); } - onChangeVendor(e) { - store.changedVendor(e.target.value); + + onChangeVendor(e: React.ChangeEvent) { + store.changedVendor(Number(e.target.value)); } - onChangeReferenceNo(e) { + + onChangeReferenceNo(e: React.ChangeEvent) { store.changedReferenceNo(e.target.value); } + render() { return (
    -
    - Vendor Information +
    + Vendor Information
    @@ -149,7 +152,7 @@ class PurchaseInvoiceHeader extends React.Component{
    Date
    + value={store.purchaseInvoice.invoiceDate !== undefined ? store.purchaseInvoice.invoiceDate.toISOString().substring(0, 10) : new Date(Date.now()).toISOString().substring(0, 10) } />
    Reference no.
    @@ -166,22 +169,21 @@ class PurchaseInvoiceHeader extends React.Component{ ); } } +const ObservedPurchaseInvoiceHeader = observer(PurchaseInvoiceHeader); -@observer -class PurchaseInvoiceLines extends React.Component{ +class PurchaseInvoiceLines extends React.Component { addLineItem() { if (store.validationLine()) { + const itemId: string = (document.getElementById("optNewItemId") as HTMLInputElement).value; + const measurementId: string = (document.getElementById("optNewMeasurementId") as HTMLInputElement).value; + const quantity: string = (document.getElementById("txtNewQuantity") as HTMLInputElement).value; + const amount: string = (document.getElementById("txtNewAmount") as HTMLInputElement).value; + const discount: string = (document.getElementById("txtNewDiscount") as HTMLInputElement).value; + const code = (document.getElementById("txtNewCode") as HTMLInputElement).value; - var itemId, measurementId, quantity, amount, discount; - itemId = (document.getElementById("optNewItemId") as HTMLInputElement).value; - measurementId = (document.getElementById("optNewMeasurementId") as HTMLInputElement).value; - quantity = (document.getElementById("txtNewQuantity") as HTMLInputElement).value; - amount = (document.getElementById("txtNewAmount") as HTMLInputElement).value; - discount = (document.getElementById("txtNewDiscount") as HTMLInputElement).value; - - //console.log(`itemId: ${itemId} | measurementId: ${measurementId} | quantity: ${quantity} | amount: ${amount} | discount: ${discount}`); - store.addLineItem(0, itemId, measurementId, quantity, amount, discount); + store.addLineItem(0, Number(itemId), Number(measurementId), + Number(quantity), Number(amount), Number(discount), code); (document.getElementById("optNewItemId") as HTMLInputElement).value = ""; (document.getElementById("txtNewCode") as HTMLInputElement).value = ""; @@ -192,48 +194,48 @@ class PurchaseInvoiceLines extends React.Component{ } } - onClickRemoveLineItem(i, e) { + onClickRemoveLineItem(i: number) { store.removeLineItem(i); } - onChangeQuantity(e) { + onChangeQuantity(e: any) { store.updateLineItem(e.target.name, "quantity", e.target.value); } - onChangeAmount(e) { + onChangeAmount(e: any) { store.updateLineItem(e.target.name, "amount", e.target.value); } - onChangeDiscount(e) { + onChangeDiscount(e: any) { store.updateLineItem(e.target.name, "discount", e.target.value); } - onChangeItem(e) { + onChangeItem(e: any) { store.updateLineItem(e.target.name, "itemId", e.target.value); } - onChangeCode(e) { + onChangeCode(e: any) { store.updateLineItem(e.target.name, "code", e.target.value); } - onFocusOutItem(e, isNew, i) { - - var isExisting = false; - for (var x = 0; x < store.commonStore.items.length; x++) { - if (store.commonStore.items[x].code == i.target.value) { + onFocusOutItem(e: any, isNew: boolean, i: any) { + let isExisting = false; + for (let x = 0; x < store.commonStore.items.length; x++) { + const lineItem = store.commonStore.items[x] as PurchaseInvoiceLine; + if (lineItem.code == i.target.value) { isExisting = true; if (isNew) { - (document.getElementById("optNewItemId") as HTMLInputElement).value = store.commonStore.items[x].id; - (document.getElementById("optNewMeasurementId") as HTMLInputElement).value = store.commonStore.items[x].sellMeasurementId; - (document.getElementById("txtNewAmount") as HTMLInputElement).value = store.commonStore.items[x].price; + (document.getElementById("optNewItemId") as HTMLInputElement).value = lineItem.id.toString(); + (document.getElementById("optNewMeasurementId") as HTMLInputElement).value = lineItem.measurementId.toString(); + (document.getElementById("txtNewAmount") as HTMLInputElement).value = lineItem.amount.toString(); (document.getElementById("txtNewQuantity") as HTMLInputElement).value = "1"; - document.getElementById("txtNewCode").style.borderColor = ""; + document.getElementById("txtNewCode")!.style.borderColor = ""; } else { - store.updateLineItem(e, "itemId", store.commonStore.items[x].id); - store.updateLineItem(e, "measurementId", store.commonStore.items[x].sellMeasurementId); - store.updateLineItem(e, "amount", store.commonStore.items[x].price); + store.updateLineItem(e, "itemId", lineItem.id); + store.updateLineItem(e, "measurementId", lineItem.measurementId); + store.updateLineItem(e, "amount", lineItem.amount); store.updateLineItem(e, "quantity", 1); i.target.style.borderColor = ""; } @@ -247,7 +249,7 @@ class PurchaseInvoiceLines extends React.Component{ (document.getElementById("optNewMeasurementId") as HTMLInputElement).value = ""; (document.getElementById("txtNewAmount") as HTMLInputElement).value = ""; (document.getElementById("txtNewQuantity") as HTMLInputElement).value = ""; - document.getElementById("txtNewCode").style.borderColor = '#FF0000'; + document.getElementById("txtNewCode")!.style.borderColor = '#FF0000'; //document.getElementById("txtNewCode").appendChild(span); // document.getElementById("txtNewCode").style.border = 'solid'; } @@ -265,9 +267,10 @@ class PurchaseInvoiceLines extends React.Component{ } render() { - var newLine = 0; - var lineItems = []; - for (var i = 0; i < store.purchaseInvoice.purchaseInvoiceLines.length; i++) { + let newLine = 0; + const lineItems = []; + let lastIndex = 0; + for (let i = 0; i < store.purchaseInvoice.purchaseInvoiceLines.length; i++) { newLine = newLine + 10; lineItems.push( @@ -286,6 +289,7 @@ class PurchaseInvoiceLines extends React.Component{ ); + lastIndex = i; } return (
    @@ -312,7 +316,7 @@ class PurchaseInvoiceLines extends React.Component{ - + @@ -331,9 +335,9 @@ class PurchaseInvoiceLines extends React.Component{ ); } } +const ObservedPurchaseInvoiceLines = observer(PurchaseInvoiceLines); -@observer -class PurchaseInvoiceTotals extends React.Component{ +class PurchaseInvoiceTotals extends React.Component { render() { return (
    @@ -352,28 +356,28 @@ class PurchaseInvoiceTotals extends React.Component{ } } -@observer -export default class PurchaseInvoice extends React.Component { +class PurchaseInvoice extends React.Component { render() { return (
    - +
    - - - + + +
    - + - +
    ); } } +const ObservedPurchaseInvoice = observer(PurchaseInvoice); -ReactDOM.render(, document.getElementById("divPurchaseInvoice")); \ No newline at end of file +export default ObservedPurchaseInvoice; diff --git a/src/AccountGoWeb/Scripts/Purchasing/PurchaseOrder.tsx b/src/GoodBooksReact/src/components/Purchasing/PurchaseOrder.tsx similarity index 70% rename from src/AccountGoWeb/Scripts/Purchasing/PurchaseOrder.tsx rename to src/GoodBooksReact/src/components/Purchasing/PurchaseOrder.tsx index d15f59f06..12dbc3456 100644 --- a/src/AccountGoWeb/Scripts/Purchasing/PurchaseOrder.tsx +++ b/src/GoodBooksReact/src/components/Purchasing/PurchaseOrder.tsx @@ -1,5 +1,4 @@ import * as React from "react"; -import * as ReactDOM from "react-dom"; import {observer} from "mobx-react"; import * as accounting from "accounting"; @@ -9,22 +8,23 @@ import SelectLineItem from "../Shared/Components/SelectLineItem"; import SelectLineMeasurement from "../Shared/Components/SelectLineMeasurement"; import PurchaseOrderStore from "../Shared/Stores/Purchasing/PurchaseOrderStore"; +import PurchaseOrderLine from "../Shared/Stores/Purchasing/PurchaseOrderLine"; -let purchId = window.location.search.split("?purchId=")[1]; +const purchId = window.location.search.split("?purchId=")[1]; -let store = new PurchaseOrderStore(purchId); +const store = new PurchaseOrderStore(Number(purchId)); -let baseUrl = location.protocol - + "//" + location.hostname - + (location.port && ":" + location.port) - + "/"; +// let baseUrl: string = location.protocol +// + "//" + location.hostname +// + (location.port && ":" + location.port) +// + "/"; -@observer -class ValidationErrors extends React.Component{ +class ValidationErrors extends React.Component { render() { if (store.validationErrors !== undefined && store.validationErrors.length > 0) { - var errors = []; + const errors: string[] = []; store.validationErrors.map(function (item, index) { + const errors: React.ReactNode[] = []; errors.push(
  • {item}
  • ); }); return ( @@ -39,22 +39,22 @@ class ValidationErrors extends React.Component{ return null; } } +const ObservedValidationErrors = observer(ValidationErrors); - - -@observer -class PurchaseOrderHeader extends React.Component{ - onChangeOrderDate(e) { - store.changedOrderDate(e.target.value); +class PurchaseOrderHeader extends React.Component { + onChangeOrderDate(e: React.ChangeEvent) { + store.changedOrderDate(new Date(e.target.value)); } - onChangeReferenceNo(e) { + + onChangeReferenceNo(e: React.ChangeEvent) { store.changedReferenceNo(e.target.value); } + render() { return (
    -
    - Vendor Information +
    + Vendor Information
    @@ -72,7 +72,7 @@ class PurchaseOrderHeader extends React.Component{
    Date
    + value={store.purchaseOrder.orderDate !== undefined ? store.purchaseOrder.orderDate.toString().substring(0, 10) : new Date(Date.now()).toISOString().substring(0, 10) } />
    Reference no.
    @@ -89,70 +89,67 @@ class PurchaseOrderHeader extends React.Component{ ); } } +const ObservedPurchaseOrderHeader = observer(PurchaseOrderHeader); -@observer -class PurchaseOrderLines extends React.Component{ +class PurchaseOrderLines extends React.Component { addLineItem() { if (store.validationLine()) { - - var itemId, measurementId, quantity, amount, discount, code; - itemId = (document.getElementById("optNewItemId") as HTMLInputElement).value; - measurementId = (document.getElementById("optNewMeasurementId") as HTMLInputElement).value; - quantity = (document.getElementById("txtNewQuantity") as HTMLInputElement).value; - amount = (document.getElementById("txtNewAmount") as HTMLInputElement).value; - discount = (document.getElementById("txtNewDiscount") as HTMLInputElement).value; - code = (document.getElementById("txtNewCode") as HTMLInputElement).value; - - //console.log(`itemId: ${itemId} | measurementId: ${measurementId} | quantity: ${quantity} | amount: ${amount} | discount: ${discount}`); - store.addLineItem(0, itemId, measurementId, quantity, amount, discount, code); - - (document.getElementById("optNewItemId") as HTMLInputElement).value = ""; - (document.getElementById("txtNewCode") as HTMLInputElement).value = ""; - (document.getElementById("optNewMeasurementId") as HTMLInputElement).value = ""; - (document.getElementById("txtNewQuantity") as HTMLInputElement).value = "1"; - (document.getElementById("txtNewAmount") as HTMLInputElement).value = ""; - (document.getElementById("txtNewDiscount") as HTMLInputElement).value = ""; - } + const itemId: string = (document.getElementById("optNewItemId") as HTMLInputElement).value; + const measurementId: string = (document.getElementById("optNewMeasurementId") as HTMLInputElement).value; + const quantity: string = (document.getElementById("txtNewQuantity") as HTMLInputElement).value; + const amount: string = (document.getElementById("txtNewAmount") as HTMLInputElement).value; + const discount: string = (document.getElementById("txtNewDiscount") as HTMLInputElement).value; + const code: string = (document.getElementById("txtNewCode") as HTMLInputElement).value; + + store.addLineItem(0, Number(itemId), Number(measurementId), Number(quantity), Number(amount), Number(discount), code); + + (document.getElementById("optNewItemId") as HTMLInputElement).value = ""; + (document.getElementById("txtNewCode") as HTMLInputElement).value = ""; + (document.getElementById("optNewMeasurementId") as HTMLInputElement).value = ""; + (document.getElementById("txtNewQuantity") as HTMLInputElement).value = "1"; + (document.getElementById("txtNewAmount") as HTMLInputElement).value = ""; + (document.getElementById("txtNewDiscount") as HTMLInputElement).value = ""; + } } - onClickRemoveLineItem(i, e) { + onClickRemoveLineItem(i: number) { store.removeLineItem(i); } - onChangeQuantity(e) { + onChangeQuantity(e: any) { store.updateLineItem(e.target.name, "quantity", e.target.value); } - onChangeAmount(e) { + onChangeAmount(e: any) { store.updateLineItem(e.target.name, "amount", e.target.value); } - onChangeDiscount(e) { + onChangeDiscount(e: any) { store.updateLineItem(e.target.name, "discount", e.target.value); } - onChangeCode(e) { + onChangeCode(e: any) { store.updateLineItem(e.target.name, "code", e.target.value); } - onFocusOutItem(e, isNew, i) { - - var isExisting = false; - for (var x = 0; x < store.commonStore.items.length; x++) { - if (store.commonStore.items[x].code == i.target.value) { + onFocusOutItem(e: any, isNew: boolean, i: any) { + let isExisting = false; + for (let x = 0; x < store.commonStore.items.length; x++) { + const lineItem = store.commonStore.items[x] as PurchaseOrderLine; + if (lineItem.code == i.target.value) { isExisting = true; if (isNew) { - (document.getElementById("optNewItemId") as HTMLInputElement).value = store.commonStore.items[x].id; - (document.getElementById("optNewMeasurementId") as HTMLInputElement).value = store.commonStore.items[x].sellMeasurementId; - (document.getElementById("txtNewAmount") as HTMLInputElement).value = store.commonStore.items[x].price; + (document.getElementById("optNewItemId") as HTMLInputElement).value = lineItem.id.toString(); + (document.getElementById("optNewMeasurementId") as HTMLInputElement).value = lineItem.measurementId.toString(); + (document.getElementById("txtNewAmount") as HTMLInputElement).value = lineItem.amount.toString(); (document.getElementById("txtNewQuantity") as HTMLInputElement).value = "1"; - document.getElementById("txtNewCode").style.borderColor = ""; + document.getElementById("txtNewCode")!.style.borderColor = ""; } else { - store.updateLineItem(e, "itemId", store.commonStore.items[x].id); - store.updateLineItem(e, "measurementId", store.commonStore.items[x].sellMeasurementId); - store.updateLineItem(e, "amount", store.commonStore.items[x].price); + store.updateLineItem(e, "itemId", lineItem.id); + store.updateLineItem(e, "measurementId", lineItem.measurementId); + store.updateLineItem(e, "amount", lineItem.amount); store.updateLineItem(e, "quantity", 1); i.target.style.borderColor = ""; } @@ -166,7 +163,7 @@ class PurchaseOrderLines extends React.Component{ (document.getElementById("optNewMeasurementId") as HTMLInputElement).value = ""; (document.getElementById("txtNewAmount") as HTMLInputElement).value = ""; (document.getElementById("txtNewQuantity") as HTMLInputElement).value = ""; - document.getElementById("txtNewCode").style.borderColor = '#FF0000'; + document.getElementById("txtNewCode")!.style.borderColor = '#FF0000'; //document.getElementById("txtNewCode").appendChild(span); // document.getElementById("txtNewCode").style.border = 'solid'; } @@ -184,9 +181,10 @@ class PurchaseOrderLines extends React.Component{ } render() { - var newLine = 0; - var lineItems = []; - for (var i = 0; i < store.purchaseOrder.purchaseOrderLines.length; i++) { + let newLine = 0; + const lineItems: JSX.Element[] = []; + let lastIndex: number = 0; + for (let i = 0; i < store.purchaseOrder.purchaseOrderLines.length; i++) { newLine = newLine + 10; lineItems.push( @@ -205,6 +203,7 @@ class PurchaseOrderLines extends React.Component{ ); + lastIndex = i; } return (
    @@ -231,7 +230,7 @@ class PurchaseOrderLines extends React.Component{ - + @@ -250,9 +249,9 @@ class PurchaseOrderLines extends React.Component{ ); } } +const ObservedPurchaseOrderLines = observer(PurchaseOrderLines); -@observer -class PurchaseOrderTotals extends React.Component{ +class PurchaseOrderTotals extends React.Component { render() { return (
    @@ -270,15 +269,15 @@ class PurchaseOrderTotals extends React.Component{ ); } } +const ObservedPurchaseOrderTotals = observer(PurchaseOrderTotals); -@observer -class EditButton extends React.Component { +class EditButton extends React.Component { onClickEditButton() { // Remove " disabledControl" from current className - var nodes = document.getElementById("divPurchaseOrderForm").getElementsByTagName('*'); - for (var i = 0; i < nodes.length; i++) { - var subStringLength = nodes[i].className.length - " disabledControl".length; - nodes[i].className = nodes[i].className.substring(0, subStringLength); + const nodes = document.getElementById("divPurchaseOrderForm")?.getElementsByTagName('*'); + for (let i = 0; i < nodes!.length; i++) { + const subStringLength = nodes![i].className.length - " disabledControl".length; + nodes![i].className = nodes![i].className.substring(0, subStringLength); } store.changedEditMode(true); @@ -296,9 +295,10 @@ class EditButton extends React.Component { } } +const ObservedEditButton = observer(EditButton); -class SavePurchaseOrderButton extends React.Component{ - saveNewPurchaseOrder(e) { +class SavePurchaseOrderButton extends React.Component { + saveNewPurchaseOrder() { store.savePurchaseOrder(); } @@ -309,9 +309,9 @@ class SavePurchaseOrderButton extends React.Component{ } } -class CancelPurchaseOrderButton extends React.Component{ +class CancelPurchaseOrderButton extends React.Component { cancelOnClick() { - let baseUrl = location.protocol + const baseUrl = location.protocol + "//" + location.hostname + (location.port && ":" + location.port) + "/"; @@ -328,18 +328,18 @@ class CancelPurchaseOrderButton extends React.Component{ } } -export default class AddPurchaseOrder extends React.Component { +class AddPurchaseOrder extends React.Component { render() { return (
    - +
    - - - - + + + +
    @@ -349,5 +349,6 @@ export default class AddPurchaseOrder extends React.Component { ); } } +const ObservedAddPurchaseOrder = observer(AddPurchaseOrder); -ReactDOM.render(, document.getElementById("divPurchaseOrder")); \ No newline at end of file +export default ObservedAddPurchaseOrder; \ No newline at end of file diff --git a/src/AccountGoWeb/Scripts/Sales/SalesInvoice.tsx b/src/GoodBooksReact/src/components/Sales/SalesInvoice.tsx similarity index 70% rename from src/AccountGoWeb/Scripts/Sales/SalesInvoice.tsx rename to src/GoodBooksReact/src/components/Sales/SalesInvoice.tsx index 036b28e23..97560e2eb 100644 --- a/src/AccountGoWeb/Scripts/Sales/SalesInvoice.tsx +++ b/src/GoodBooksReact/src/components/Sales/SalesInvoice.tsx @@ -1,31 +1,25 @@ import * as React from "react"; -import * as ReactDOM from "react-dom"; import {observer} from "mobx-react"; +// import from "accounting" npm package import * as accounting from "accounting"; import SelectCustomer from "../Shared/Components/SelectCustomer"; import SelectPaymentTerm from "../Shared/Components/SelectPaymentTerm"; import SelectLineItem from "../Shared/Components/SelectLineItem"; import SelectLineMeasurement from "../Shared/Components/SelectLineMeasurement"; - +import SalesInvoiceLine from "../Shared/Stores/Sales/SalesInvoiceLine"; import SalesInvoiceStore from "../Shared/Stores/Sales/SalesInvoiceStore"; -let orderId = window.location.search.split("?orderId=")[1]; -let invoiceId = window.location.search.split("?invoiceId=")[1]; - -let store = new SalesInvoiceStore(orderId, invoiceId); - -let baseUrl = location.protocol - + "//" + location.hostname - + (location.port && ":" + location.port) - + "/"; +const orderId = window.location.search.split("?orderId=")[1]; +const invoiceId = window.location.search.split("?invoiceId=")[1]; +const store = new SalesInvoiceStore(Number(orderId), Number(invoiceId)); -@observer -class ValidationErrors extends React.Component{ +class ValidationErrors extends React.Component { render() { if (store.validationErrors !== undefined && store.validationErrors.length > 0) { - var errors = []; - store.validationErrors.map(function (item, index) { + const errors: string[] = []; + store.validationErrors.map(function (item: string, index: number) { + const errors: React.ReactNode[] = []; errors.push(
  • {item}
  • ); }); return ( @@ -40,13 +34,14 @@ class ValidationErrors extends React.Component{ return null; } } -@observer -class EditButton extends React.Component{ +const ObservedValidationErrors = observer(ValidationErrors); + +class EditButton extends React.Component { onClickEditButton() { // Remove " disabledControl" from current className - var nodes = document.getElementById("divSalesInvoiceForm").getElementsByTagName('*'); - for (var i = 0; i < nodes.length; i++) { - var subStringLength = nodes[i].className.length - " disabledControl".length; + const nodes = document.getElementById("divSalesInvoiceForm")!.getElementsByTagName('*'); + for (let i = 0; i < nodes.length; i++) { + const subStringLength = nodes[i].className.length - " disabledControl".length; nodes[i].className = nodes[i].className.substring(0, subStringLength); } store.changedEditMode(true) @@ -63,13 +58,13 @@ class EditButton extends React.Component{ ); } } +const ObservedEditButton = observer(EditButton); -@observer -class SaveInvoiceButton extends React.Component{ - saveNewSalesInvoice(e) { +class SaveInvoiceButton extends React.Component { + saveNewSalesInvoice() { store.saveNewSalesInvoice(); } - onChangeReferenceNo(e) { + onChangeReferenceNo(e: React.ChangeEvent) { store.changedReferenceNo(e.target.value); } render() { @@ -82,10 +77,11 @@ class SaveInvoiceButton extends React.Component{ ); } } +const ObservedSaveInvoiceButton = observer(SaveInvoiceButton); -class CancelInvoiceButton extends React.Component{ +class CancelInvoiceButton extends React.Component { cancelOnClick() { - let baseUrl = location.protocol + const baseUrl = location.protocol + "//" + location.hostname + (location.port && ":" + location.port) + "/"; @@ -101,10 +97,10 @@ class CancelInvoiceButton extends React.Component{ ); } } +const ObservedCancelInvoiceButton = observer(CancelInvoiceButton); -@observer -class PrintButton extends React.Component{ - printOnClick(e) { +class PrintButton extends React.Component { + printOnClick() { store.printInvoice(); } @@ -118,10 +114,10 @@ class PrintButton extends React.Component{ ); } } +const ObservedPrintButton = observer(PrintButton); -@observer -class PostButton extends React.Component{ - postOnClick(e) { +class PostButton extends React.Component { + postOnClick() { store.postInvoice(); } @@ -135,20 +131,20 @@ class PostButton extends React.Component{ ); } } +const ObservedPostButton = observer(PostButton); -@observer -class SalesInvoiceHeader extends React.Component{ - onChangeInvoiceDate(e) { - store.changedInvoiceDate(e.target.value); +class SalesInvoiceHeader extends React.Component { + onChangeInvoiceDate(e: React.ChangeEvent) { + store.changedInvoiceDate(new Date(e.target.value)); } - onChangeReferenceNo(e) { + onChangeReferenceNo(e: React.ChangeEvent) { store.changedReferenceNo(e.target.value); } render() { return (
    - Customer Information + Customer Information
    @@ -165,7 +161,7 @@ class SalesInvoiceHeader extends React.Component{
    Date
    + value={store.salesInvoice.invoiceDate !== undefined ? store.salesInvoice.invoiceDate.toISOString().substring(0, 10) : new Date(Date.now()).toISOString().substring(0, 10) } />
    Reference no.
    @@ -177,23 +173,21 @@ class SalesInvoiceHeader extends React.Component{ ); } } +const ObservedSalesInvoiceHeader = observer(SalesInvoiceHeader); -@observer -class SalesInvoiceLines extends React.Component{ +class SalesInvoiceLines extends React.Component { addLineItem() { if (store.validationLine()) { - - var itemId, measurementId, quantity, amount, discount, code; - itemId = (document.getElementById("optNewItemId") as HTMLInputElement).value; - measurementId = (document.getElementById("optNewMeasurementId") as HTMLInputElement).value; - quantity = (document.getElementById("txtNewQuantity") as HTMLInputElement).value; - amount = (document.getElementById("txtNewAmount") as HTMLInputElement).value; - discount = (document.getElementById("txtNewDiscount") as HTMLInputElement).value; - code = (document.getElementById("txtNewCode") as HTMLInputElement).value; + const itemId: string = (document.getElementById("optNewItemId") as HTMLInputElement).value; + const measurementId: string = (document.getElementById("optNewMeasurementId") as HTMLInputElement).value; + const quantity: string = (document.getElementById("txtNewQuantity") as HTMLInputElement).value; + const amount: string = (document.getElementById("txtNewAmount") as HTMLInputElement).value; + const discount: string = (document.getElementById("txtNewDiscount") as HTMLInputElement).value; + const code: string = (document.getElementById("txtNewCode") as HTMLInputElement).value; //console.log(`itemId: ${itemId} | measurementId: ${measurementId} | quantity: ${quantity} | amount: ${amount} | discount: ${discount}`); - store.addLineItem(0, itemId, measurementId, quantity, amount, discount, code); + store.addLineItem(0, Number(itemId), Number(measurementId), Number(quantity), Number(amount), Number(discount), code); (document.getElementById("optNewItemId") as HTMLInputElement).value = ""; (document.getElementById("txtNewCode") as HTMLInputElement).value = ""; @@ -204,71 +198,68 @@ class SalesInvoiceLines extends React.Component{ } } - onClickRemoveLineItem(i, e) { + onClickRemoveLineItem(i: number) { store.removeLineItem(i); } - onChangeQuantity(e) { + onChangeQuantity(e: any) { store.updateLineItem(e.target.name, "quantity", e.target.value); } - onChangeAmount(e) { + onChangeAmount(e: any) { store.updateLineItem(e.target.name, "amount", e.target.value); } - onChangeDiscount(e) { + onChangeDiscount(e: any) { store.updateLineItem(e.target.name, "discount", e.target.value); } - onChangeCode(e) { + onChangeCode(e: any) { store.updateLineItem(e.target.name, "code", e.target.value); } - - onFocusOutItem(e, isNew, i) { - - var isExisting = false; - for (var x = 0; x < store.commonStore.items.length; x++) { - if (store.commonStore.items[x].code == i.target.value) { + onFocusOutItem(e: any, isNew: boolean, i: any) { + let isExisting: boolean = false; + for (let x = 0; x < store.commonStore.items.length; x++) { + const lineitem: SalesInvoiceLine = store.commonStore.items[x] as SalesInvoiceLine + if (lineitem.code === i.target.value) { isExisting = true; if (isNew) { - (document.getElementById("optNewItemId") as HTMLInputElement).value = store.commonStore.items[x].id; - (document.getElementById("optNewMeasurementId") as HTMLInputElement).value = store.commonStore.items[x].sellMeasurementId; - (document.getElementById("txtNewAmount") as HTMLInputElement).value = store.commonStore.items[x].price; + (document.getElementById("optNewItemId") as HTMLInputElement).value = lineitem.id.toString(); + (document.getElementById("optNewMeasurementId") as HTMLInputElement).value = lineitem.measurementId.toString(); + (document.getElementById("txtNewAmount") as HTMLInputElement).value = lineitem.amount.toString(); (document.getElementById("txtNewQuantity") as HTMLInputElement).value = "1"; - document.getElementById("txtNewCode").style.borderColor = ""; + document.getElementById("txtNewCode")!.style.borderColor = ""; } else { - store.updateLineItem(e, "itemId", store.commonStore.items[x].id); - store.updateLineItem(e, "measurementId", store.commonStore.items[x].sellMeasurementId); - store.updateLineItem(e, "amount", store.commonStore.items[x].price); - store.updateLineItem(e, "quantity", 1); + store.updateLineItem(e, "itemId", lineitem.id.toString()); + store.updateLineItem(e, "measurementId", lineitem.measurementId.toString()); + store.updateLineItem(e, "amount", lineitem.amount.toString()); + store.updateLineItem(e, "quantity", "1"); i.target.style.borderColor = ""; } } } - if (!isExisting) - + if (!isExisting) { if (isNew) { (document.getElementById("optNewItemId") as HTMLInputElement).value = ""; (document.getElementById("optNewMeasurementId") as HTMLInputElement).value = ""; (document.getElementById("txtNewAmount") as HTMLInputElement).value = ""; (document.getElementById("txtNewQuantity") as HTMLInputElement).value = ""; - document.getElementById("txtNewCode").style.borderColor = '#FF0000'; + document.getElementById("txtNewCode")!.style.borderColor = '#FF0000'; } else { - i.target.style.borderColor = "red"; - } - + } } render() { - var newLine = 0; - var lineItems = []; - for (var i = 0; i < store.salesInvoice.salesInvoiceLines.length; i++) { + let newLine = 0; + const lineItems: JSX.Element[] = []; + let lastIndex: number = 0; + for (let i = 0; i < store.salesInvoice.salesInvoiceLines.length; i++) { newLine = newLine + 10; lineItems.push( @@ -287,6 +278,7 @@ class SalesInvoiceLines extends React.Component{ ); + lastIndex = i; } return (
    @@ -313,7 +305,7 @@ class SalesInvoiceLines extends React.Component{ - + @@ -332,9 +324,9 @@ class SalesInvoiceLines extends React.Component{ ); } } +const ObservedSalesInvoiceLines = observer(SalesInvoiceLines); -@observer -class SalesInvoiceTotals extends React.Component{ +class SalesInvoiceTotals extends React.Component { render() { return (
    @@ -352,30 +344,31 @@ class SalesInvoiceTotals extends React.Component{ ); } } +const ObservedSalesInvoiceTotals = observer(SalesInvoiceTotals); -@observer -export default class SalesInvoice extends React.Component { +class SalesInvoice extends React.Component { render() { return (
    - +
    - - - - + + + +
    - - - - + + + +
    ); } } +const ObservedSalesInvoice = observer(SalesInvoice); -ReactDOM.render(, document.getElementById("divSalesInvoice")); \ No newline at end of file +export default ObservedSalesInvoice; diff --git a/src/AccountGoWeb/Scripts/Sales/SalesOrder.tsx b/src/GoodBooksReact/src/components/Sales/SalesOrder.tsx similarity index 72% rename from src/AccountGoWeb/Scripts/Sales/SalesOrder.tsx rename to src/GoodBooksReact/src/components/Sales/SalesOrder.tsx index 076104c5d..ee0015eb4 100644 --- a/src/AccountGoWeb/Scripts/Sales/SalesOrder.tsx +++ b/src/GoodBooksReact/src/components/Sales/SalesOrder.tsx @@ -1,5 +1,4 @@ import * as React from "react"; -import * as ReactDOM from "react-dom"; import { observer } from "mobx-react"; import * as accounting from "accounting"; @@ -9,22 +8,22 @@ import SelectLineItem from "../Shared/Components/SelectLineItem"; import SelectLineMeasurement from "../Shared/Components/SelectLineMeasurement"; import SalesOrderStore from "../Shared/Stores/Sales/SalesOrderStore"; +import SalesOrderLine from "../Shared/Stores/Sales/SalesOrderLine"; -let quotationId = window.location.search.split("?quotationId=")[1]; -let orderId = window.location.search.split("?orderId=")[1]; +const quotationId = window.location.search.split("?quotationId=")[1]; +const orderId = window.location.search.split("?orderId=")[1]; +const store = new SalesOrderStore(Number(quotationId), Number(orderId)); -let store = new SalesOrderStore(quotationId, orderId); - -let baseUrl = location.protocol + "//" + location.hostname + (location.port && ":" + location.port) + "/"; - -@observer -class ValidationErrors extends React.Component { +class ValidationErrors extends React.Component { render() { if (store.validationErrors !== undefined && store.validationErrors.length > 0) { - var errors = []; - store.validationErrors.map(function(item, index) { + const errors: string[] = []; + + store.validationErrors.map(function(item: string, index: number) { + const errors: React.ReactNode[] = []; errors.push(
  • {item}
  • ); }); + return (
      {errors}
    @@ -34,9 +33,10 @@ class ValidationErrors extends React.Component { return null; } } +const ObservedValidationErrors = observer(ValidationErrors); -class SaveOrderButton extends React.Component { - saveNewSalesOrder(e) { +class SaveOrderButton extends React.Component { + saveNewSalesOrder() { store.saveNewSalesOrder(); } @@ -52,9 +52,9 @@ class SaveOrderButton extends React.Component { } } -class CancelOrderButton extends React.Component { +class CancelOrderButton extends React.Component { cancelOnClick() { - let baseUrl = location.protocol + "//" + location.hostname + (location.port && ":" + location.port) + "/"; + const baseUrl = location.protocol + "//" + location.hostname + (location.port && ":" + location.port) + "/"; window.location.href = baseUrl + "sales/salesorders"; } @@ -73,21 +73,20 @@ class CancelOrderButton extends React.Component { } } -@observer -class SalesOrderHeader extends React.Component { - onChangeOrderDate(e) { - store.changedOrderDate(e.target.value); +class SalesOrderHeader extends React.Component { + onChangeOrderDate(e: React.ChangeEvent) { + store.changedOrderDate(new Date(e.target.value)); } - onChangeReferenceNo(e) { + onChangeReferenceNo(e: React.ChangeEvent) { store.changedReferenceNo(e.target.value); } render() { return ( -
    -
    - Customer Information +
    +
    + Customer Information
    -
    +
    Customer
    @@ -102,7 +101,7 @@ class SalesOrderHeader extends React.Component {
    Date
    + value={store.salesOrder.orderDate !== undefined ? store.salesOrder.orderDate.toString().substring(0, 10) : new Date(Date.now()).toISOString().substring(0, 10)} />
    Reference no.
    @@ -118,20 +117,19 @@ class SalesOrderHeader extends React.Component { ); } } +const ObservedSalesOrderHeader = observer(SalesOrderHeader); -@observer -class SalesOrderLines extends React.Component { +class SalesOrderLines extends React.Component { addLineItem() { if (store.validationLine()) { - var itemId, measurementId, quantity, amount, discount, code; - itemId = (document.getElementById("optNewItemId") as HTMLInputElement).value; - measurementId = (document.getElementById("optNewMeasurementId") as HTMLInputElement).value; - quantity = (document.getElementById("txtNewQuantity") as HTMLInputElement).value; - amount = (document.getElementById("txtNewAmount") as HTMLInputElement).value; - discount = (document.getElementById("txtNewDiscount") as HTMLInputElement).value; - code = (document.getElementById("txtNewCode") as HTMLInputElement).value; - //console.log(`itemId: ${itemId} | measurementId: ${measurementId} | quantity: ${quantity} | amount: ${amount} | discount: ${discount}`); - store.addLineItem(0, itemId, measurementId, quantity, amount, discount, code); + const itemId: string = (document.getElementById("optNewItemId") as HTMLInputElement).value; + const measurementId: string = (document.getElementById("optNewMeasurementId") as HTMLInputElement).value; + const quantity: string = (document.getElementById("txtNewQuantity") as HTMLInputElement).value; + const amount: string = (document.getElementById("txtNewAmount") as HTMLInputElement).value; + const discount: string = (document.getElementById("txtNewDiscount") as HTMLInputElement).value; + const code: string = (document.getElementById("txtNewCode") as HTMLInputElement).value; + + store.addLineItem(0, Number(itemId), Number(measurementId), Number(quantity), Number(amount), Number(discount), code); (document.getElementById("optNewItemId") as HTMLInputElement).value = ""; (document.getElementById("txtNewCode") as HTMLInputElement).value = ""; @@ -142,42 +140,43 @@ class SalesOrderLines extends React.Component { } } - onClickRemoveLineItem(i, e) { + onClickRemoveLineItem(i: number) { store.removeLineItem(i); } - onChangeQuantity(e) { + onChangeQuantity(e: any) { store.updateLineItem(e.target.name, "quantity", e.target.value); } - onChangeAmount(e) { + onChangeAmount(e: any) { store.updateLineItem(e.target.name, "amount", e.target.value); } - onChangeDiscount(e) { + onChangeDiscount(e: any) { store.updateLineItem(e.target.name, "discount", e.target.value); } - onChangeCode(e) { + onChangeCode(e: any) { store.updateLineItem(e.target.name, "code", e.target.value); } - onFocusOutItem(e, isNew, i) { - var isExisting = false; - for (var x = 0; x < store.commonStore.items.length; x++) { - if (store.commonStore.items[x].code == i.target.value) { + onFocusOutItem(e: any, isNew: boolean, i: any) { + let isExisting = false; + for (let x = 0; x < store.commonStore.items.length; x++) { + const lineItem = store.commonStore.items[x] as SalesOrderLine; + if (lineItem.code == i.target.value) { isExisting = true; if (isNew) { - (document.getElementById("optNewItemId") as HTMLInputElement).value = store.commonStore.items[x].id; + (document.getElementById("optNewItemId") as HTMLInputElement).value = lineItem.id.toString(); (document.getElementById("optNewMeasurementId") as HTMLInputElement).value = - store.commonStore.items[x].sellMeasurementId; - (document.getElementById("txtNewAmount") as HTMLInputElement).value = store.commonStore.items[x].price; + lineItem.measurementId.toString(); + (document.getElementById("txtNewAmount") as HTMLInputElement).value = lineItem.amount.toString(); (document.getElementById("txtNewQuantity") as HTMLInputElement).value = "1"; - document.getElementById("txtNewCode").style.borderColor = ""; + document.getElementById("txtNewCode")!.style.borderColor = ""; } else { - store.updateLineItem(e, "itemId", store.commonStore.items[x].id); - store.updateLineItem(e, "measurementId", store.commonStore.items[x].sellMeasurementId); - store.updateLineItem(e, "amount", store.commonStore.items[x].price); + store.updateLineItem(e, "itemId", lineItem.id); + store.updateLineItem(e, "measurementId", lineItem.measurementId); + store.updateLineItem(e, "amount", lineItem.amount); store.updateLineItem(e, "quantity", 1); i.target.style.borderColor = ""; } @@ -190,7 +189,7 @@ class SalesOrderLines extends React.Component { (document.getElementById("optNewMeasurementId") as HTMLInputElement).value = ""; (document.getElementById("txtNewAmount") as HTMLInputElement).value = ""; (document.getElementById("txtNewQuantity") as HTMLInputElement).value = ""; - document.getElementById("txtNewCode").style.borderColor = "#FF0000"; + document.getElementById("txtNewCode")!.style.borderColor = "#FF0000"; //document.getElementById("txtNewCode").appendChild(span); // document.getElementById("txtNewCode").style.border = 'solid'; } else { @@ -206,9 +205,10 @@ class SalesOrderLines extends React.Component { //{store.salesOrder.salesOrderLines[i].itemId} render() { - var newLine = 0; - var lineItems = []; - for (var i = 0; i < store.salesOrder.salesOrderLines.length; i++) { + let newLine = 0; + const lineItems: JSX.Element[] = []; + let lastIndex: number = 0; + for (let i = 0; i < store.salesOrder.salesOrderLines.length; i++) { newLine = newLine + 10; lineItems.push( @@ -266,6 +266,7 @@ class SalesOrderLines extends React.Component { ); + lastIndex = i; } return (
    @@ -299,7 +300,7 @@ class SalesOrderLines extends React.Component { className="form-control" type="text" id="txtNewCode" - onBlur={this.onFocusOutItem.bind(this, i, true)} + onBlur={this.onFocusOutItem.bind(this, lastIndex, true)} /> @@ -328,9 +329,9 @@ class SalesOrderLines extends React.Component { ); } } +const ObservedSalesOrderLines = observer(SalesOrderLines); -@observer -class SalesOrderTotals extends React.Component { +class SalesOrderTotals extends React.Component { render() { return (
    @@ -354,14 +355,14 @@ class SalesOrderTotals extends React.Component { ); } } +const ObservedSalesOrderTotals = observer(SalesOrderTotals); -@observer class EditButton extends React.Component { onClickEditButton() { // Remove " disabledControl" from current className - var nodes = document.getElementById("divSalesOrderForm").getElementsByTagName("*"); - for (var i = 0; i < nodes.length; i++) { - var subStringLength = nodes[i].className.length - " disabledControl".length; + const nodes = document.getElementById("divSalesOrderForm")!.getElementsByTagName("*"); + for (let i = 0; i < nodes.length; i++) { + const subStringLength = nodes[i].className.length - " disabledControl".length; nodes[i].className = nodes[i].className.substring(0, subStringLength); } @@ -386,19 +387,20 @@ class EditButton extends React.Component { ); } } +const ObservedEditButton = observer(EditButton); -export default class SalesOrder extends React.Component { +class SalesOrder extends React.Component { render() { return (
    - +
    - - - - + + + +
    @@ -408,5 +410,7 @@ export default class SalesOrder extends React.Component { ); } } +const ObservedSalesOrder = observer(SalesOrder); + +export default ObservedSalesOrder; -ReactDOM.render(, document.getElementById("divSalesOrder")); diff --git a/src/GoodBooksReact/src/components/Section.tsx b/src/GoodBooksReact/src/components/Section.tsx new file mode 100644 index 000000000..0f8e52bdd --- /dev/null +++ b/src/GoodBooksReact/src/components/Section.tsx @@ -0,0 +1,17 @@ +import { ReactNode } from "react" + +type SectionProps = { + title?: string, + children: ReactNode +} + +const Section = ({title = "My subheading", children}: SectionProps) => { + return( +
    +

    {title}

    +

    {children}

    +
    + ) +} + +export default Section diff --git a/src/AccountGoWeb/Scripts/Shared/Components/SelectAccount.tsx b/src/GoodBooksReact/src/components/Shared/Components/SelectAccount.tsx similarity index 75% rename from src/AccountGoWeb/Scripts/Shared/Components/SelectAccount.tsx rename to src/GoodBooksReact/src/components/Shared/Components/SelectAccount.tsx index 6674f29de..21d8e0c3d 100644 --- a/src/AccountGoWeb/Scripts/Shared/Components/SelectAccount.tsx +++ b/src/GoodBooksReact/src/components/Shared/Components/SelectAccount.tsx @@ -1,15 +1,14 @@ import * as React from "react"; import {observer} from "mobx-react"; -@observer -export default class SelectVoucherType extends React.Component{ - onChangeAccount(e) { +class SelectVoucherType extends React.Component{ + onChangeAccount(e: any) { if (this.props.row !== undefined) this.props.store.updateLineItem(this.props.row, "accountId", e.target.value); } render() { - var options = []; - this.props.store.commonStore.accounts.map(function (account) { + const options: JSX.Element[] = []; + this.props.store.commonStore.accounts.map(function (account: any) { return ( options.push() ); @@ -22,4 +21,7 @@ export default class SelectVoucherType extends React.Component{ ); } -} \ No newline at end of file +} +const ObservedSelectVoucherType = observer(SelectVoucherType); + +export default ObservedSelectVoucherType; diff --git a/src/AccountGoWeb/Scripts/Shared/Components/SelectCustomer.tsx b/src/GoodBooksReact/src/components/Shared/Components/SelectCustomer.tsx similarity index 76% rename from src/AccountGoWeb/Scripts/Shared/Components/SelectCustomer.tsx rename to src/GoodBooksReact/src/components/Shared/Components/SelectCustomer.tsx index a0840148d..5f51f8837 100644 --- a/src/AccountGoWeb/Scripts/Shared/Components/SelectCustomer.tsx +++ b/src/GoodBooksReact/src/components/Shared/Components/SelectCustomer.tsx @@ -1,12 +1,11 @@ import * as React from "react"; import {observer} from "mobx-react"; -@observer -export default class SelectCustomer extends React.Component{ - onChangeCustomer(e) { +class SelectCustomer extends React.Component{ + onChangeCustomer(e: any) { this.props.store.changedCustomer(e.target.value); - for (var i = 0; i < this.props.store.commonStore.customers.length; i++) { + for (let i = 0; i < this.props.store.commonStore.customers.length; i++) { if (this.props.store.commonStore.customers[i].id === parseInt(e.target.value)) { this.props.store.changedPaymentTerm(this.props.store.commonStore.customers[i].paymentTermId); } @@ -18,8 +17,8 @@ export default class SelectCustomer extends React.Component{ } render() { - var options = []; - this.props.store.commonStore.customers.map(function (customer) { + const options: JSX.Element[] = []; + this.props.store.commonStore.customers.map(function (customer: any) { return ( options.push() @@ -33,4 +32,7 @@ export default class SelectCustomer extends React.Component{ ); } -} \ No newline at end of file +} +const ObservedSelectCustomer = observer(SelectCustomer); + +export default ObservedSelectCustomer; diff --git a/src/AccountGoWeb/Scripts/Shared/Components/SelectDebitCredit.tsx b/src/GoodBooksReact/src/components/Shared/Components/SelectDebitCredit.tsx similarity index 73% rename from src/AccountGoWeb/Scripts/Shared/Components/SelectDebitCredit.tsx rename to src/GoodBooksReact/src/components/Shared/Components/SelectDebitCredit.tsx index f260047c1..22abb1bb3 100644 --- a/src/AccountGoWeb/Scripts/Shared/Components/SelectDebitCredit.tsx +++ b/src/GoodBooksReact/src/components/Shared/Components/SelectDebitCredit.tsx @@ -1,14 +1,13 @@ import * as React from "react"; import {observer} from "mobx-react"; -@observer -export default class SelectDebiCredit extends React.Component{ - onChangeDebitCredit(e) { +class SelectDebiCredit extends React.Component{ + onChangeDebitCredit(e: any) { if (this.props.row !== undefined) this.props.store.updateLineItem(this.props.row, "drcr", e.target.value); } render() { - var options = []; + const options: JSX.Element[] = []; options.push(); options.push(); @@ -19,4 +18,7 @@ export default class SelectDebiCredit extends React.Component{ ); } -} \ No newline at end of file +} +const ObservedSelectDebiCredit = observer(SelectDebiCredit); + +export default ObservedSelectDebiCredit; \ No newline at end of file diff --git a/src/AccountGoWeb/Scripts/Shared/Components/SelectLineItem.tsx b/src/GoodBooksReact/src/components/Shared/Components/SelectLineItem.tsx similarity index 90% rename from src/AccountGoWeb/Scripts/Shared/Components/SelectLineItem.tsx rename to src/GoodBooksReact/src/components/Shared/Components/SelectLineItem.tsx index cbb85ece2..dee644266 100644 --- a/src/AccountGoWeb/Scripts/Shared/Components/SelectLineItem.tsx +++ b/src/GoodBooksReact/src/components/Shared/Components/SelectLineItem.tsx @@ -1,9 +1,8 @@ import * as React from "react"; import {observer} from "mobx-react"; -@observer -export default class SelectLineItem extends React.Component{ - onChangeItem(e) { +class SelectLineItem extends React.Component{ + onChangeItem(e: any) { if (this.props.row !== undefined) this.props.store.updateLineItem(this.props.row, "itemId", e.target.value); @@ -36,11 +35,9 @@ export default class SelectLineItem extends React.Component{ } } - - for (var i = 0; i < this.props.store.commonStore.items.length; i++) { + for (let i = 0; i < this.props.store.commonStore.items.length; i++) { if (this.props.store.commonStore.items[i].id === parseInt(e.target.value)) { - if (this.props.row !== undefined) { this.props.store.updateLineItem(this.props.row, "measurementId", this.props.store.commonStore.items[i].sellMeasurementId); this.props.store.updateLineItem(this.props.row, "amount", this.props.store.commonStore.items[i].price); @@ -62,8 +59,8 @@ export default class SelectLineItem extends React.Component{ } render() { - var options = []; - this.props.store.commonStore.items.map(function (item) { + const options: JSX.Element[] = []; + this.props.store.commonStore.items.map(function (item: any) { return ( options.push() ); @@ -76,4 +73,7 @@ export default class SelectLineItem extends React.Component{ ); } -} \ No newline at end of file +} +const ObservedSelectLineItem = observer(SelectLineItem); + +export default ObservedSelectLineItem; \ No newline at end of file diff --git a/src/AccountGoWeb/Scripts/Shared/Components/SelectLineMeasurement.tsx b/src/GoodBooksReact/src/components/Shared/Components/SelectLineMeasurement.tsx similarity index 72% rename from src/AccountGoWeb/Scripts/Shared/Components/SelectLineMeasurement.tsx rename to src/GoodBooksReact/src/components/Shared/Components/SelectLineMeasurement.tsx index a9c95481b..58555a1da 100644 --- a/src/AccountGoWeb/Scripts/Shared/Components/SelectLineMeasurement.tsx +++ b/src/GoodBooksReact/src/components/Shared/Components/SelectLineMeasurement.tsx @@ -1,15 +1,14 @@ import * as React from "react"; import {observer} from "mobx-react"; -@observer -export default class SelectLineMeasurement extends React.Component{ - onChangeMeasurement(e) { +class SelectLineMeasurement extends React.Component{ + onChangeMeasurement(e: any) { if (this.props.row !== undefined) this.props.store.updateLineItem(this.props.row, "measurementId", e.target.value); } render() { - var options = []; - this.props.store.commonStore.measurements.map(function (measurement) { + const options: JSX.Element[] = []; + this.props.store.commonStore.measurements.map(function (measurement: any) { return ( options.push() ); @@ -22,4 +21,7 @@ export default class SelectLineMeasurement extends React.Component{ ); } -} \ No newline at end of file +} +const ObservedSelectLineMeasurement = observer(SelectLineMeasurement); + +export default ObservedSelectLineMeasurement; diff --git a/src/AccountGoWeb/Scripts/Shared/Components/SelectPaymentTerm.tsx b/src/GoodBooksReact/src/components/Shared/Components/SelectPaymentTerm.tsx similarity index 72% rename from src/AccountGoWeb/Scripts/Shared/Components/SelectPaymentTerm.tsx rename to src/GoodBooksReact/src/components/Shared/Components/SelectPaymentTerm.tsx index ee8bc7fc1..a779056de 100644 --- a/src/AccountGoWeb/Scripts/Shared/Components/SelectPaymentTerm.tsx +++ b/src/GoodBooksReact/src/components/Shared/Components/SelectPaymentTerm.tsx @@ -1,15 +1,14 @@ import * as React from "react"; import {observer} from "mobx-react"; -@observer -export default class SelectPaymentTerm extends React.Component{ - onChangePaymentTerm(e) { +class SelectPaymentTerm extends React.Component{ + onChangePaymentTerm(e: any) { this.props.store.changedPaymentTerm(e.target.value); } render() { - var options = []; - this.props.store.commonStore.paymentTerms.map(function (term) { + const options: JSX.Element[] = []; + this.props.store.commonStore.paymentTerms.map(function (term: any) { return ( options.push() ); @@ -22,4 +21,7 @@ export default class SelectPaymentTerm extends React.Component{ ); } -} \ No newline at end of file +} +const ObservedSelectPaymentTerm = observer(SelectPaymentTerm); + +export default ObservedSelectPaymentTerm; \ No newline at end of file diff --git a/src/AccountGoWeb/Scripts/Shared/Components/SelectQuotationStatus.tsx b/src/GoodBooksReact/src/components/Shared/Components/SelectQuotationStatus.tsx similarity index 70% rename from src/AccountGoWeb/Scripts/Shared/Components/SelectQuotationStatus.tsx rename to src/GoodBooksReact/src/components/Shared/Components/SelectQuotationStatus.tsx index faf7679ac..9c01ce70d 100644 --- a/src/AccountGoWeb/Scripts/Shared/Components/SelectQuotationStatus.tsx +++ b/src/GoodBooksReact/src/components/Shared/Components/SelectQuotationStatus.tsx @@ -1,15 +1,14 @@ import * as React from "react"; import {observer} from "mobx-react"; -@observer -export default class SelectQuotationStatus extends React.Component { - onChangeQuoteStatus(e) { +class SelectQuotationStatus extends React.Component { + onChangeQuoteStatus(e: any) { this.props.store.changedQuoteStatus(e.target.value); } render() { - var options = []; - this.props.store.commonStore.salesQuotationStatus.map(function (item) { + const options: React.ReactNode[] = []; + this.props.store.commonStore.salesQuotationStatus.map(function (item: any) { return ( options.push() ); @@ -24,6 +23,7 @@ export default class SelectQuotationStatus extends React.Component { ); } +} +const ObservedSelectQuotationStatus = observer(SelectQuotationStatus); - -} \ No newline at end of file +export default ObservedSelectQuotationStatus; diff --git a/src/AccountGoWeb/Scripts/Shared/Components/SelectVendor.tsx b/src/GoodBooksReact/src/components/Shared/Components/SelectVendor.tsx similarity index 76% rename from src/AccountGoWeb/Scripts/Shared/Components/SelectVendor.tsx rename to src/GoodBooksReact/src/components/Shared/Components/SelectVendor.tsx index 66aa7865f..7866304cd 100644 --- a/src/AccountGoWeb/Scripts/Shared/Components/SelectVendor.tsx +++ b/src/GoodBooksReact/src/components/Shared/Components/SelectVendor.tsx @@ -1,12 +1,11 @@ import * as React from "react"; import {observer} from "mobx-react"; -@observer -export default class SelectVendor extends React.Component{ - onChangeVendor(e) { +class SelectVendor extends React.Component{ + onChangeVendor(e: any) { this.props.store.changedVendor(e.target.value); - for (var i = 0; i < this.props.store.commonStore.vendors.length; i++) { + for (let i = 0; i < this.props.store.commonStore.vendors.length; i++) { if (this.props.store.commonStore.vendors[i].id === parseInt(e.target.value)) { this.props.store.changedPaymentTerm(this.props.store.commonStore.vendors[i].paymentTermId); @@ -18,8 +17,8 @@ export default class SelectVendor extends React.Component{ } render() { - var options = []; - this.props.store.commonStore.vendors.map(function (vendor) { + const options: JSX.Element[] = []; + this.props.store.commonStore.vendors.map(function (vendor: any) { return ( options.push() ); @@ -32,4 +31,7 @@ export default class SelectVendor extends React.Component{ ); } -} \ No newline at end of file +} +const ObservedSelectVendor = observer(SelectVendor); + +export default ObservedSelectVendor; diff --git a/src/AccountGoWeb/Scripts/Shared/Components/SelectVoucherType.tsx b/src/GoodBooksReact/src/components/Shared/Components/SelectVoucherType.tsx similarity index 59% rename from src/AccountGoWeb/Scripts/Shared/Components/SelectVoucherType.tsx rename to src/GoodBooksReact/src/components/Shared/Components/SelectVoucherType.tsx index ef11df2ae..a0f57c519 100644 --- a/src/AccountGoWeb/Scripts/Shared/Components/SelectVoucherType.tsx +++ b/src/GoodBooksReact/src/components/Shared/Components/SelectVoucherType.tsx @@ -1,14 +1,13 @@ import * as React from "react"; import {observer} from "mobx-react"; -@observer -export default class SelectVoucherType extends React.Component{ - onChangeVoucherType(e) { +class SelectVoucherType extends React.Component{ + onChangeVoucherType(e: any) { this.props.store.changedVoucherType(e.target.value); } render() { - var options = []; + const options: JSX.Element[] = []; options.push(); options.push(); options.push(); @@ -16,10 +15,19 @@ export default class SelectVoucherType extends React.Component{ options.push(); return ( - + + {options} ); } -} \ No newline at end of file +} + +const ObservedSelectVoucherType = observer(SelectVoucherType); + +export default ObservedSelectVoucherType; \ No newline at end of file diff --git a/src/GoodBooksReact/src/components/Shared/Config/index.tsx b/src/GoodBooksReact/src/components/Shared/Config/index.tsx new file mode 100644 index 000000000..636528c40 --- /dev/null +++ b/src/GoodBooksReact/src/components/Shared/Config/index.tsx @@ -0,0 +1,5 @@ +const Config = { + API_URL: `http://localhost:8001/api/`, +}; + +export default Config; \ No newline at end of file diff --git a/src/GoodBooksReact/src/components/Shared/Stores/AppState.tsx b/src/GoodBooksReact/src/components/Shared/Stores/AppState.tsx new file mode 100644 index 000000000..b48e3a804 --- /dev/null +++ b/src/GoodBooksReact/src/components/Shared/Stores/AppState.tsx @@ -0,0 +1,2 @@ +export default class AppState { +} \ No newline at end of file diff --git a/src/GoodBooksReact/src/components/Shared/Stores/Common/CommonStore.tsx b/src/GoodBooksReact/src/components/Shared/Stores/Common/CommonStore.tsx new file mode 100644 index 000000000..48f9b2748 --- /dev/null +++ b/src/GoodBooksReact/src/components/Shared/Stores/Common/CommonStore.tsx @@ -0,0 +1,152 @@ +import {makeObservable, observable} from 'mobx'; +import axios from "axios"; +import Config from '../../Config'; + +export default class CommonStore { + customers: string[] = []; + paymentTerms: string[] = []; + items: object[] = []; + measurements: string[] = []; + vendors: string[] = []; + accounts: string[] = []; + salesQuotationStatus: string[] = []; + + constructor() { + this.loadCustomersLookup(); + this.loadPaymentTermsLookup(); + this.loadItemsLookup(); + this.loadMeasurementsLookup(); + this.loadVendorsLookup(); + this.loadAccountsLookup(); + this.loadQuotationStatusLookup(); + + makeObservable(this, { + customers: observable, + paymentTerms: observable, + items: observable, + measurements: observable, + vendors: observable, + accounts: observable, + salesQuotationStatus: observable, + }); + } + + loadCustomersLookup() { + const localCustomers: string[] = []; + + axios.get(Config.API_URL + "common/customers") + .then(result => { + const data = result.data; + for (let i = 0; i < Object.keys(data).length; i++) { + localCustomers.push(data[i]); + } + this.customers = localCustomers; + }); + } + + loadPaymentTermsLookup() { + const localPaymentTerms: string[] = []; + axios.get(Config.API_URL + "common/paymentterms") + .then(result => { + const data = result.data; + for (let i = 0; i < Object.keys(data).length; i++) { + localPaymentTerms.push(data[i]); + } + this.paymentTerms = localPaymentTerms; + }); + } + + loadVendorsLookup() { + const localVendors: string[] = []; + + axios.get(Config.API_URL + "common/vendors") + .then(response => { + const data = response.data; + for (let i = 0; i < Object.keys(data).length; i++) { + localVendors.push(data[i]); + } + this.vendors = localVendors; + }) + .catch(error => { + console.error(error); + }); + } + + loadItemsLookup() { + const localItems: object[] = []; + + axios.get(Config.API_URL + "common/items") + .then(response => { + const data = response.data; + for (let i = 0; i < Object.keys(data).length; i++) { + localItems.push(data[i]); + } + this.items = localItems; + }) + .catch(error => { + console.error(error); + }); + } + + loadMeasurementsLookup() { + const localMeasurements: string[] = []; + axios.get(Config.API_URL + "common/measurements") + .then(result => { + const data = result.data; + for (let i = 0; i < Object.keys(data).length; i++) { + localMeasurements.push(data[i]); + } + this.measurements = localMeasurements; + }); + } + + loadQuotationStatusLookup() { + const localQuotationStatus: string[] = []; + axios.get(Config.API_URL + "common/salesquotationstatus") + .then(result => { + const data = result.data; + for (let i = 0; i < Object.keys(data).length; i++) + { + localQuotationStatus.push(data[i]); + } + this.salesQuotationStatus = localQuotationStatus; + }) + } + + loadAccountsLookup() { + const localAccounts: string[] = []; + axios.get(Config.API_URL + "common/postingaccounts") + .then(result => { + const data: string[] = result.data; + for (let i = 0; i < Object.keys(data).length; i++) { + localAccounts.push(data[i]); + } + this.accounts = localAccounts; + }); + } + + getApplicableTaxes(itemId: number, partyId: number) { + const result = axios.get(Config.API_URL + "tax/gettax?itemId=" + itemId + "&partyId=" + partyId); + result.then(function (result) { + return result.data; + }); + } + + getSalesLineTaxAmount(quantity: number, amount: number, discount: number, taxes: Array<{ rate: number }>) { + let lineTaxTotal = 0; + amount = (amount * quantity) - discount; + taxes.map(function (tax) { + lineTaxTotal = lineTaxTotal + (amount - (amount / (1 + (tax.rate / 100)))); + }); + return lineTaxTotal; + } + + getPurhcaseLineTaxAmount(quantity: number, amount: number, discount: number, taxes: Array<{ rate: number }>) { + let lineTaxTotal = 0; + amount = (amount * quantity) - discount; + taxes.map(function (tax) { + lineTaxTotal = lineTaxTotal + (amount - (amount / (1 + (tax.rate / 100)))); + }); + return lineTaxTotal; + } +} \ No newline at end of file diff --git a/src/AccountGoWeb/Scripts/Shared/Stores/Financials/JournalEntry.tsx b/src/GoodBooksReact/src/components/Shared/Stores/Financials/JournalEntry.tsx similarity index 73% rename from src/AccountGoWeb/Scripts/Shared/Stores/Financials/JournalEntry.tsx rename to src/GoodBooksReact/src/components/Shared/Stores/Financials/JournalEntry.tsx index a368e9362..c64e11634 100644 --- a/src/AccountGoWeb/Scripts/Shared/Stores/Financials/JournalEntry.tsx +++ b/src/GoodBooksReact/src/components/Shared/Stores/Financials/JournalEntry.tsx @@ -2,10 +2,10 @@ export default class JournalEntry { id: number; - voucherType: number; - journalDate: Date; - referenceNo: string; - memo: string; + voucherType: number = 0; + journalDate: Date = new Date(); + referenceNo: string = ""; + memo: string = ""; posted: boolean; readyForPosting: boolean; journalEntryLines: JournalEntryLine[] = []; diff --git a/src/AccountGoWeb/Scripts/Shared/Stores/Financials/JournalEntryLine.tsx b/src/GoodBooksReact/src/components/Shared/Stores/Financials/JournalEntryLine.tsx similarity index 52% rename from src/AccountGoWeb/Scripts/Shared/Stores/Financials/JournalEntryLine.tsx rename to src/GoodBooksReact/src/components/Shared/Stores/Financials/JournalEntryLine.tsx index f4ab923cd..934894a2c 100644 --- a/src/AccountGoWeb/Scripts/Shared/Stores/Financials/JournalEntryLine.tsx +++ b/src/GoodBooksReact/src/components/Shared/Stores/Financials/JournalEntryLine.tsx @@ -1,11 +1,11 @@ export default class JournalEntryLine { id: number = 0; - accountId: number; - drcr: number; - amount: number; - memo: string; + accountId: number = 0; + drcr: number = 0; + amount: number = 0; + memo: string = ""; - constructor(id, accountId, drcr, amount, memo) { + constructor(id: number, accountId: number, drcr: number, amount: number, memo: string) { this.id = id; this.accountId = accountId; this.drcr = drcr; diff --git a/src/AccountGoWeb/Scripts/Shared/Stores/Financials/JournalEntryStore.tsx b/src/GoodBooksReact/src/components/Shared/Stores/Financials/JournalEntryStore.tsx similarity index 59% rename from src/AccountGoWeb/Scripts/Shared/Stores/Financials/JournalEntryStore.tsx rename to src/GoodBooksReact/src/components/Shared/Stores/Financials/JournalEntryStore.tsx index c54244074..86a3a1e6a 100644 --- a/src/AccountGoWeb/Scripts/Shared/Stores/Financials/JournalEntryStore.tsx +++ b/src/GoodBooksReact/src/components/Shared/Stores/Financials/JournalEntryStore.tsx @@ -1,27 +1,25 @@ -import {observable, extendObservable, action, intercept, reaction} from 'mobx'; -import * as axios from "axios"; -import * as d3 from "d3"; - -import Config = require("Config"); +import {observable, extendObservable, makeObservable} from 'mobx'; +import axios from "axios"; +import Config from '../../Config'; import JournalEntry from './JournalEntry'; import JournalEntryLine from './JournalEntryLine'; import CommonStore from "../Common/CommonStore"; -let baseUrl = location.protocol +const baseUrl = location.protocol + "//" + location.hostname + (location.port && ":" + location.port) + "/"; export default class JournalEntryStore { - originalJournalEntry; - journalEntry; - commonStore; - @observable validationErrors; - @observable isDirty = false; - @observable initialized = false; - @observable editMode = false; + originalJournalEntry: JournalEntry = new JournalEntry(); + journalEntry: JournalEntry = new JournalEntry(); + commonStore: CommonStore = new CommonStore(); + validationErrors: string[] = []; + isDirty = false; + initialized = false; + editMode = false; constructor() { this.commonStore = new CommonStore(); @@ -36,26 +34,33 @@ export default class JournalEntryStore { journalEntryLines: this.journalEntry.journalEntryLines }); - let journalEntryId = window.location.search.split("?id=")[1]; + makeObservable(this, { + validationErrors: observable, + isDirty: observable, + initialized: observable, + editMode: observable, + }); + + const journalEntryId = window.location.search.split("?id=")[1]; if (journalEntryId !== undefined) this.getJournalEntry(parseInt(journalEntryId)) else this.changedEditMode(true); } - changeIsDirty(dirty) { + changeIsDirty(dirty: boolean) { this.isDirty = dirty; } - changeInitialized(initialized) { + changeInitialized(initialized: boolean) { this.initialized = initialized; } getJournalEntry(journalEntryId: number) { - axios.get(Config.apiUrl + "financials/journalentry?id=" + journalEntryId) - .then(function (result) { - for (var i = 0; i < result.data.journalEntryLines.length; i++) { - var item = result.data.journalEntryLines[i]; + axios.get(Config.API_URL + "financials/journalentry?id=" + journalEntryId) + .then((result) => { + for (let i = 0; i < result.data.journalEntryLines.length; i++) { + const item = result.data.journalEntryLines[i]; this.addLineItem(item.id, item.accountId, item.drCr, item.amount, item.memo); } this.journalEntry.id = result.data.id; @@ -66,29 +71,32 @@ export default class JournalEntryStore { this.journalEntry.posted = result.data.posted; this.journalEntry.readyForPosting = result.data.readyForPosting; - var nodes = document.getElementById("divJournalEntryForm").getElementsByTagName('*'); - for (var i = 0; i < nodes.length; i++) { + const nodes = document.getElementById("divJournalEntryForm")!.getElementsByTagName('*'); + for (let i = 0; i < nodes.length; i++) { nodes[i].className += " disabledControl"; } - }.bind(this)); + }); } saveNewJournalEntry() { if (this.validation() && this.validationErrors.length == 0) { - axios.post(Config.apiUrl + "financials/savejournalentry", JSON.stringify(this.journalEntry), + axios.post(Config.API_URL + "financials/savejournalentry", JSON.stringify(this.journalEntry), { headers: { 'Content-type': 'application/json' } }) - .then(function (response) { + .then(() => { window.location.href = baseUrl + 'financials/journalentries'; }) - .catch(function (error) { - error.data.map(function (err) { - this.validationErrors.push(err); - }.bind(this)); - }.bind(this)) + .catch((error) => { + if (axios.isAxiosError(error)) { + this.validationErrors.push(`Status: ${error.status} - Message: ${error.response?.data}`); + } else { + console.error(error); + this.validationErrors.push(`Error: ${error}`); + } + }) } } @@ -106,7 +114,7 @@ export default class JournalEntryStore { if (this.journalEntry.journalEntryLines.length < 2) this.validationErrors.push("You need at lest 2 journal entry lines for debit and credit."); if (this.journalEntry.journalEntryLines !== undefined && this.journalEntry.journalEntryLines.length > 0) { - for (var i = 0; i < this.journalEntry.journalEntryLines.length; i++) { + for (let i = 0; i < this.journalEntry.journalEntryLines.length; i++) { if (this.journalEntry.journalEntryLines[i].accountId === undefined) this.validationErrors.push("Account is required."); if (this.journalEntry.journalEntryLines[i].drcr === undefined) @@ -122,54 +130,58 @@ export default class JournalEntryStore { postJournal() { if (this.validation() && this.validationErrors.length == 0) { - axios.post(Config.apiUrl + "financials/postjournalentry", JSON.stringify(this.journalEntry), + axios.post(Config.API_URL + "financials/postjournalentry", JSON.stringify(this.journalEntry), { headers: { 'Content-type': 'application/json' } }) - .then(function (response) { + .then(() => { window.location.href = baseUrl + 'financials/journalentries'; }) - .catch(function (error) { - error.data.map(function (err) { - this.validationErrors.push(err); - }.bind(this)); - }.bind(this)) + .catch((error) => { + if (axios.isAxiosError(error)) { + this.validationErrors.push(`Status: ${error.status} - Message: ${error.response?.data}`); + } else { + console.error(error); + this.validationErrors.push(`Error: ${error}`); + } + }) } } - addLineItem(id, accountId, drcr, amount, memo) { - var newLineItem = new JournalEntryLine(id, accountId, drcr, amount, memo); + addLineItem(id: number, accountId: number, drcr: number, amount: number, memo: string) { + const newLineItem = new JournalEntryLine(id, accountId, drcr, amount, memo); this.journalEntry.journalEntryLines.push(extendObservable(newLineItem, newLineItem)); } - updateLineItem(row, targetProperty, value) { - if (this.journalEntry.journalEntryLines.length > 0) - this.journalEntry.journalEntryLines[row][targetProperty] = value; + updateLineItem(row: number, targetProperty: keyof JournalEntryLine, value: string | number) { + if (this.journalEntry.journalEntryLines.length > 0) { + (this.journalEntry.journalEntryLines[row] as Record)[targetProperty] = value; + } } - removeLineItem(row) { + removeLineItem(row: number) { this.journalEntry.journalEntryLines.splice(row, 1); } - changedJournalDate(date) { + changedJournalDate(date: Date) { this.journalEntry.journalDate = date; } - changedReferenceNo(refNo) { + changedReferenceNo(refNo: string) { this.journalEntry.referenceNo = refNo; } - changedMemo(memo) { + changedMemo(memo: string) { this.journalEntry.memo = memo; } - changedVoucherType(type) { + changedVoucherType(type: number) { this.journalEntry.voucherType = type; } - changedEditMode(editMode) { + changedEditMode(editMode: boolean) { this.editMode = editMode; } } \ No newline at end of file diff --git a/src/AccountGoWeb/Scripts/Shared/Stores/Financials/JournalEntryUIStore.tsx b/src/GoodBooksReact/src/components/Shared/Stores/Financials/JournalEntryUIStore.tsx similarity index 51% rename from src/AccountGoWeb/Scripts/Shared/Stores/Financials/JournalEntryUIStore.tsx rename to src/GoodBooksReact/src/components/Shared/Stores/Financials/JournalEntryUIStore.tsx index 1cd2a4b2b..778d96a3c 100644 --- a/src/AccountGoWeb/Scripts/Shared/Stores/Financials/JournalEntryUIStore.tsx +++ b/src/GoodBooksReact/src/components/Shared/Stores/Financials/JournalEntryUIStore.tsx @@ -1,7 +1,4 @@ -import {observable, autorun, reaction} from 'mobx'; -import * as mobx from "mobx"; - -import JournalEntryStore from "./JournalEntryStore"; +import JournalEntryStore from "./JournalEntryStore"; export default class JournalEntryUIStore { store; diff --git a/src/GoodBooksReact/src/components/Shared/Stores/Purchasing/PurchaseInvoice.tsx b/src/GoodBooksReact/src/components/Shared/Stores/Purchasing/PurchaseInvoice.tsx new file mode 100644 index 000000000..3afbb0cae --- /dev/null +++ b/src/GoodBooksReact/src/components/Shared/Stores/Purchasing/PurchaseInvoice.tsx @@ -0,0 +1,21 @@ +import PurchaseInvoiceLine from "./PurchaseInvoiceLine"; + +export default class PurchaseInvoice { + id: number = 0; + fromPurchaseOrderId: number = 0; + vendorId: number = 0; + invoiceDate: Date = new Date(); + paymentTermId: number = 0; + referenceNo: string = ""; + posted: boolean = false; + readyForPosting: boolean = false; + purchaseInvoiceLines: PurchaseInvoiceLine[] = []; + statusId: number = 0; + + constructor() { + this.id = 0; + this.posted = false; + this.readyForPosting = false; + + } +} \ No newline at end of file diff --git a/src/AccountGoWeb/Scripts/Shared/Stores/Sales/SalesInvoiceLine.tsx b/src/GoodBooksReact/src/components/Shared/Stores/Purchasing/PurchaseInvoiceLine.tsx similarity index 67% rename from src/AccountGoWeb/Scripts/Shared/Stores/Sales/SalesInvoiceLine.tsx rename to src/GoodBooksReact/src/components/Shared/Stores/Purchasing/PurchaseInvoiceLine.tsx index 24b35ab0c..da3570653 100644 --- a/src/AccountGoWeb/Scripts/Shared/Stores/Sales/SalesInvoiceLine.tsx +++ b/src/GoodBooksReact/src/components/Shared/Stores/Purchasing/PurchaseInvoiceLine.tsx @@ -1,5 +1,5 @@ -export default class SalesInvoiceLine { - id: number; +export default class PurchaseInvoiceLine { + id: number = 0; itemId: number; measurementId: number; quantity: number; @@ -8,7 +8,8 @@ remainingQtyToInvoice: number; code: string; - constructor(id, itemId, measurementId, quantity, amount, discount, code) { + constructor(id: number, itemId: number, measurementId: number, + quantity: number, amount: number, discount: number, code: string) { this.id = id; this.itemId = itemId; this.measurementId = measurementId; diff --git a/src/AccountGoWeb/Scripts/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx b/src/GoodBooksReact/src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx similarity index 60% rename from src/AccountGoWeb/Scripts/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx rename to src/GoodBooksReact/src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx index 321eee567..7447dc04a 100644 --- a/src/AccountGoWeb/Scripts/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx +++ b/src/GoodBooksReact/src/components/Shared/Stores/Purchasing/PurchaseInvoiceStore.tsx @@ -1,14 +1,13 @@ -import {observable, extendObservable, action, autorun, computed} from 'mobx'; -import * as axios from "axios"; - -import Config = require("Config"); +import {makeObservable, observable, extendObservable, autorun} from 'mobx'; +import axios from "axios"; +import Config from '../../Config'; import PurchaseInvoice from './PurchaseInvoice'; import PurchaseInvoiceLine from './PurchaseInvoiceLine'; import CommonStore from "../Common/CommonStore"; -let baseUrl = location.protocol +const baseUrl = location.protocol + "//" + location.hostname + (location.port && ":" + location.port) + "/"; @@ -16,11 +15,25 @@ let baseUrl = location.protocol export default class PurchaseOrderStore { purchaseInvoice; commonStore; - @observable validationErrors; - @observable editMode = false; - @observable purchaseInvoiceStatus; + validationErrors: string[] = []; + editMode = false; + purchaseInvoiceStatus: string = ""; + + RTotal = 0; + GTotal = 0; + TTotal = 0; + + constructor(purchId: number, invoiceId: number) { + + makeObservable(this, { + validationErrors: observable, + editMode: observable, + purchaseInvoiceStatus: observable, + RTotal: observable, + GTotal: observable, + TTotal: observable, + }); - constructor(purchId: any, invoiceId: any) { this.commonStore = new CommonStore(); this.purchaseInvoice = new PurchaseInvoice(); extendObservable(this.purchaseInvoice, { @@ -36,10 +49,9 @@ export default class PurchaseOrderStore { autorun(() => this.computeTotals()); if (purchId !== undefined) { - axios.get(Config.apiUrl + "api/purchasing/purchaseorder?id=" + purchId) - .then(function (result) { - - for (var i = 0; i < result.data.purchaseOrderLines.length; i++) { + axios.get(Config.API_URL + "purchasing/purchaseorder?id=" + purchId) + .then((result) => { + for (let i = 0; i < result.data.purchaseOrderLines.length; i++) { if (result.data.purchaseOrderLines[i].remainingQtyToInvoice == 0) continue; this.addLineItem( @@ -48,9 +60,9 @@ export default class PurchaseOrderStore { result.data.purchaseOrderLines[i].measurementId, result.data.purchaseOrderLines[i].remainingQtyToInvoice, result.data.purchaseOrderLines[i].amount, - result.data.purchaseOrderLines[i].discount + result.data.purchaseOrderLines[i].discount, + result.data.purchaseOrderLines[i].code ); - } this.purchaseInvoice.fromPurchaseOrderId = purchId; @@ -60,24 +72,24 @@ export default class PurchaseOrderStore { this.changedInvoiceDate(result.data.orderDate); this.computeTotals(); this.changedEditMode(true); - }.bind(this)) - .catch(function (error) { - }.bind(this)); + }) + .catch(() => {}); } else if (invoiceId !== undefined) { - axios.get(Config.apiUrl + "purchasing/purchaseinvoice?id=" + invoiceId) - .then(function (result) { - - for (var i = 0; i < result.data.purchaseInvoiceLines.length; i++) { + axios.get(Config.API_URL + "purchasing/purchaseinvoice?id=" + invoiceId) + .then((result) => { + for (let i = 0; i < result.data.purchaseInvoiceLines.length; i++) { this.addLineItem( result.data.purchaseInvoiceLines[i].id, result.data.purchaseInvoiceLines[i].itemId, result.data.purchaseInvoiceLines[i].measurementId, result.data.purchaseInvoiceLines[i].quantity, result.data.purchaseInvoiceLines[i].amount, - result.data.purchaseInvoiceLines[i].discount + result.data.purchaseInvoiceLines[i].discount, + result.data.purchaseInvoiceLines[i].code ); - this.updateLineItem(i, 'code', this.changeItemCode(result.data.purchaseInvoiceLines[i].itemId)); + const itemCode = this.changeItemCode(result.data.purchaseInvoiceLines[i].itemId) || ''; // Provide a default value if the item code is undefined + this.updateLineItem(i, 'code', itemCode); } this.purchaseInvoice.id = result.data.id; @@ -89,82 +101,80 @@ export default class PurchaseOrderStore { this.purchaseInvoice.readyForPosting = result.data.readyForPosting; this.getPurchaseInvoiceStatus(result.data.statusId); - this.computeTotals(); - var nodes = document.getElementById("divPurchaseInvoiceForm").getElementsByTagName('*'); - for (var i = 0; i < nodes.length; i++) { + const nodes = document.getElementById("divPurchaseInvoiceForm")!.getElementsByTagName('*'); + for (let i = 0; i < nodes.length; i++) { nodes[i].className += " disabledControl"; } - }.bind(this)) - .catch(function (error) { - }.bind(this)); - - + }) + .catch(() => {}); + } + else { + this.changedEditMode(true); } - else - this.changedEditMode(true); } - @observable RTotal = 0; - @observable GTotal = 0; - @observable TTotal = 0; - computeTotals() { - var rtotal = 0; - var ttotal = 0; - var gtotal = 0; + let rtotal = 0; + let ttotal = 0; - for (var i = 0; i < this.purchaseInvoice.purchaseInvoiceLines.length; i++) { - var lineItem = this.purchaseInvoice.purchaseInvoiceLines[i]; + for (let i = 0; i < this.purchaseInvoice.purchaseInvoiceLines.length; i++) { + const lineItem = this.purchaseInvoice.purchaseInvoiceLines[i]; rtotal = rtotal + this.getLineTotal(i); - axios.get(Config.apiUrl + "tax/gettax?itemId=" + lineItem.itemId + "&partyId=" + this.purchaseInvoice.vendorId + "&type=2") - .then(function (result) { + axios.get(Config.API_URL + "tax/gettax?itemId=" + lineItem.itemId + "&partyId=" + this.purchaseInvoice.vendorId + "&type=2") + .then((result) => { if (result.data.length > 0) { ttotal = ttotal + this.commonStore.getPurhcaseLineTaxAmount(lineItem.quantity, lineItem.amount, lineItem.discount, result.data); } this.TTotal = ttotal; this.GTotal = rtotal + ttotal; - }.bind(this)); + }); this.RTotal = rtotal; } } savePurchaseInvoice() { if (this.validation() && this.validationErrors.length === 0) { - axios.post(Config.apiUrl + "purchasing/savepurchaseinvoice", JSON.stringify(this.purchaseInvoice), + axios.post(Config.API_URL + "purchasing/savepurchaseinvoice", JSON.stringify(this.purchaseInvoice), { headers: { 'Content-type': 'application/json' } }) - .then(function (response) { + .then(() => { window.location.href = baseUrl + 'purchasing/purchaseinvoices'; }) - .catch(function (error) { - error.data.map(function (err) { - this.validationErrors.push(err); - }.bind(this)); - }.bind(this)) + .catch((error) => { + if (axios.isAxiosError(error)) { + this.validationErrors.push(`Status: ${error.status} - Message: ${error.response?.data}`); + } else { + console.error(error); + this.validationErrors.push(`Error: ${error}`); + } + }) } } postInvoice() { if (this.validation() && this.validationErrors.length === 0) { - axios.post(Config.apiUrl + "purchasing/postpurchaseinvoice", JSON.stringify(this.purchaseInvoice), + axios.post(Config.API_URL + "purchasing/postpurchaseinvoice", JSON.stringify(this.purchaseInvoice), { headers: { 'Content-type': 'application/json' } }) - .then(function (response) { + .then(() => { window.location.href = baseUrl + 'purchasing/purchaseinvoices'; }) - .catch(function (error) { - error.data.map(function (err) { - this.validationErrors.push(err); - }.bind(this)); - }.bind(this)) + .catch((error) => { + if (axios.isAxiosError(error)) { + this.validationErrors.push(`Status: ${error.status} - Message: ${error.response?.data}`); + } else { + console.error(error); + this.validationErrors.push(`Error: ${error}`); + } + }) } } @@ -179,24 +189,24 @@ export default class PurchaseOrderStore { if (this.purchaseInvoice.purchaseInvoiceLines === undefined || this.purchaseInvoice.purchaseInvoiceLines.length < 1) this.validationErrors.push("Enter at least 1 line item."); if (this.purchaseInvoice.purchaseInvoiceLines !== undefined && this.purchaseInvoice.purchaseInvoiceLines.length > 0) { - for (var i = 0; i < this.purchaseInvoice.purchaseInvoiceLines.length; i++) { + for (let i = 0; i < this.purchaseInvoice.purchaseInvoiceLines.length; i++) { if (this.purchaseInvoice.purchaseInvoiceLines[i].itemId === undefined - || this.purchaseInvoice.purchaseInvoiceLines[i].itemId === "") + || Number(this.purchaseInvoice.purchaseInvoiceLines[i].itemId) === 0) this.validationErrors.push("Item is required."); if (this.purchaseInvoice.purchaseInvoiceLines[i].measurementId === undefined - || this.purchaseInvoice.purchaseInvoiceLines[i].measurementId === "") + || Number(this.purchaseInvoice.purchaseInvoiceLines[i].measurementId) === 0) this.validationErrors.push("Uom is required."); if (this.purchaseInvoice.purchaseInvoiceLines[i].quantity === undefined - || this.purchaseInvoice.purchaseInvoiceLines[i].quantity === "" - || this.purchaseInvoice.purchaseInvoiceLines[i].quantity === 0) + || this.purchaseInvoice.purchaseInvoiceLines[i].quantity.toString() === "" + || parseInt(this.purchaseInvoice.purchaseInvoiceLines[i].quantity.toString()) === 0) this.validationErrors.push("Quantity is required."); if (this.purchaseInvoice.purchaseInvoiceLines[i].amount === undefined - || this.purchaseInvoice.purchaseInvoiceLines[i].amount === "" - || this.purchaseInvoice.purchaseInvoiceLines[i].amount === 0) + || this.purchaseInvoice.purchaseInvoiceLines[i].amount.toString() === "" + || parseInt(this.purchaseInvoice.purchaseInvoiceLines[i].amount.toString()) === 0) this.validationErrors.push("Amount is required."); if (this.getLineTotal(i) === undefined || this.getLineTotal(i).toString() === "NaN" - || this.getLineTotal(i) === 0) + || parseInt(this.getLineTotal(i).toString()) === 0) this.validationErrors.push("Invalid data."); } } @@ -207,7 +217,7 @@ export default class PurchaseOrderStore { validationLine() { this.validationErrors = []; if (this.purchaseInvoice.purchaseInvoiceLines !== undefined && this.purchaseInvoice.purchaseInvoiceLines.length > 0) { - for (var i = 0; i < this.purchaseInvoice.purchaseInvoiceLines.length; i++) { + for (let i = 0; i < this.purchaseInvoice.purchaseInvoiceLines.length; i++) { if (this.purchaseInvoice.purchaseInvoiceLines[i].itemId === undefined) this.validationErrors.push("Item is required."); if (this.purchaseInvoice.purchaseInvoiceLines[i].measurementId === undefined) @@ -222,30 +232,26 @@ export default class PurchaseOrderStore { } } else { - var itemId, measurementId, quantity, amount, discount; - itemId = (document.getElementById("optNewItemId") as HTMLInputElement).value; - measurementId = (document.getElementById("optNewMeasurementId") as HTMLInputElement).value; - quantity = (document.getElementById("txtNewQuantity") as HTMLInputElement).value; - amount = (document.getElementById("txtNewAmount") as HTMLInputElement).value; - discount = (document.getElementById("txtNewDiscount") as HTMLInputElement).value; + const itemId: number = Number((document.getElementById("optNewItemId") as HTMLInputElement).value); + const measurementId: number = Number((document.getElementById("optNewMeasurementId") as HTMLInputElement).value); + const quantity: number = Number((document.getElementById("txtNewQuantity") as HTMLInputElement).value); + const amount: number = Number((document.getElementById("txtNewAmount") as HTMLInputElement).value); - if (itemId == "" || itemId === undefined) + if (itemId == 0 || itemId === undefined) this.validationErrors.push("Item is required."); - if (measurementId == "" || measurementId === undefined) + if (measurementId == 0 || measurementId === undefined) this.validationErrors.push("Uom is required."); - if (quantity == "" || quantity === undefined) + if (quantity == 0 || quantity === undefined) this.validationErrors.push("Quantity is required."); - if (amount == "" || amount === undefined) + if (amount == 0 || amount === undefined) this.validationErrors.push("Amount is required."); } if (document.getElementById("optNewItemId")) { - var itemId, measurementId, quantity, amount, discount; - itemId = (document.getElementById("optNewItemId") as HTMLInputElement).value; - measurementId = (document.getElementById("optNewMeasurementId") as HTMLInputElement).value; - quantity = (document.getElementById("txtNewQuantity") as HTMLInputElement).value; - amount = (document.getElementById("txtNewAmount") as HTMLInputElement).value; - discount = (document.getElementById("txtNewDiscount") as HTMLInputElement).value; + const itemId: string = (document.getElementById("optNewItemId") as HTMLInputElement).value; + const measurementId: string = (document.getElementById("optNewMeasurementId") as HTMLInputElement).value; + const quantity: string = (document.getElementById("txtNewQuantity") as HTMLInputElement).value; + const amount: string = (document.getElementById("txtNewAmount") as HTMLInputElement).value; if (itemId == "" || itemId === undefined) this.validationErrors.push("Item is required."); @@ -262,49 +268,52 @@ export default class PurchaseOrderStore { } - changedReferenceNo(refNo) { + changedReferenceNo(refNo: string) { this.purchaseInvoice.referenceNo = refNo; } - changedVendor(vendorId) { + + changedVendor(vendorId: number) { this.purchaseInvoice.vendorId = vendorId; } - changedPaymentTerm(paymentTermId) { + changedPaymentTerm(paymentTermId: number) { this.purchaseInvoice.paymentTermId = paymentTermId; } - changedInvoiceDate(date) { + + changedInvoiceDate(date: Date) { this.purchaseInvoice.invoiceDate = date; } - addLineItem(id, itemId, measurementId, quantity, amount, discount) { - var newLineItem = new PurchaseInvoiceLine(id, itemId, measurementId, quantity, amount, discount); + addLineItem(id: number, itemId: number, measurementId: number, + quantity: number, amount: number, discount: number, code: string) { + const newLineItem = new PurchaseInvoiceLine(id, itemId, measurementId, quantity, amount, discount, code); this.purchaseInvoice.purchaseInvoiceLines.push(extendObservable(newLineItem, newLineItem)); } - removeLineItem(row) { + removeLineItem(row: number) { this.purchaseInvoice.purchaseInvoiceLines.splice(row, 1); } - updateLineItem(row, targetProperty, value) { + updateLineItem(row: number, targetProperty: keyof PurchaseInvoiceLine, value: string | number) { if (this.purchaseInvoice.purchaseInvoiceLines.length > 0) - this.purchaseInvoice.purchaseInvoiceLines[row][targetProperty] = value; + (this.purchaseInvoice.purchaseInvoiceLines[row] as Record)[targetProperty] = value; this.computeTotals(); } - getLineTotal(row) { + getLineTotal(row: number) { let lineSum = 0; - let lineItem = this.purchaseInvoice.purchaseInvoiceLines[row]; + const lineItem = this.purchaseInvoice.purchaseInvoiceLines[row]; lineSum = (lineItem.quantity * lineItem.amount) - lineItem.discount; return lineSum; } - changedEditMode(editMode) { + changedEditMode(editMode: boolean) { this.editMode = editMode; } - getPurchaseInvoiceStatus(statusId) { - var status = ""; + getPurchaseInvoiceStatus(statusId: number) { + let status = ""; if (statusId === 0) status = "Draft"; else if (statusId === 1) @@ -314,11 +323,12 @@ export default class PurchaseOrderStore { this.purchaseInvoiceStatus = status; } - changeItemCode(itemId) { + changeItemCode(itemId: number) { - for (var x = 0; x < this.commonStore.items.length; x++) { - if (this.commonStore.items[x].id === parseInt(itemId)) { - return this.commonStore.items[x].code; + for (let x = 0; x < this.commonStore.items.length; x++) { + const lineItem = this.commonStore.items[x] as PurchaseInvoiceLine + if (lineItem.id === itemId) { + return lineItem.code; } } } diff --git a/src/GoodBooksReact/src/components/Shared/Stores/Purchasing/PurchaseOrder.tsx b/src/GoodBooksReact/src/components/Shared/Stores/Purchasing/PurchaseOrder.tsx new file mode 100644 index 000000000..c613736b8 --- /dev/null +++ b/src/GoodBooksReact/src/components/Shared/Stores/Purchasing/PurchaseOrder.tsx @@ -0,0 +1,11 @@ +import PurchaseOrderLine from "./PurchaseOrderLine"; + +export default class PurchaseOrder { + id: number = 0; + vendorId: number = 0; + orderDate: Date = new Date(); + paymentTermId: number = 0; + referenceNo: string = ""; + statusId: number = 0; + purchaseOrderLines: PurchaseOrderLine[] = []; +} \ No newline at end of file diff --git a/src/AccountGoWeb/Scripts/Shared/Stores/Quotations/SalesQuotationLine.tsx b/src/GoodBooksReact/src/components/Shared/Stores/Purchasing/PurchaseOrderLine.tsx similarity index 61% rename from src/AccountGoWeb/Scripts/Shared/Stores/Quotations/SalesQuotationLine.tsx rename to src/GoodBooksReact/src/components/Shared/Stores/Purchasing/PurchaseOrderLine.tsx index 96b4367ef..9042a2cb3 100644 --- a/src/AccountGoWeb/Scripts/Shared/Stores/Quotations/SalesQuotationLine.tsx +++ b/src/GoodBooksReact/src/components/Shared/Stores/Purchasing/PurchaseOrderLine.tsx @@ -1,13 +1,13 @@ -export default class SalesQuotationLine { - id: number; +export default class PurchaseOrderLine { + id = 0; itemId: number; measurementId: number; quantity: number; amount: number; discount: number; - code: number; + code: string; - constructor(id, itemId, measurementId, quantity, amount, discount, code) { + constructor(id: number, itemId: number, measurementId: number, quantity: number, amount: number, discount: number, code: string) { this.id = id; this.itemId = itemId; this.measurementId = measurementId; diff --git a/src/AccountGoWeb/Scripts/Shared/Stores/Purchasing/PurchaseOrderStore.tsx b/src/GoodBooksReact/src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx similarity index 62% rename from src/AccountGoWeb/Scripts/Shared/Stores/Purchasing/PurchaseOrderStore.tsx rename to src/GoodBooksReact/src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx index 54b1823ff..38d219bfd 100644 --- a/src/AccountGoWeb/Scripts/Shared/Stores/Purchasing/PurchaseOrderStore.tsx +++ b/src/GoodBooksReact/src/components/Shared/Stores/Purchasing/PurchaseOrderStore.tsx @@ -1,26 +1,29 @@ -import {observable, extendObservable, action, autorun, computed} from 'mobx'; -import * as axios from "axios"; - -import Config = require("Config"); +import {observable, extendObservable, autorun, makeObservable} from 'mobx'; +import axios from "axios"; +import Config from '../../Config'; import PurchaseOrder from './PurchaseOrder'; import PurchaseOrderLine from './PurchaseOrderLine'; import CommonStore from "../Common/CommonStore"; -let baseUrl = location.protocol +const baseUrl = location.protocol + "//" + location.hostname + (location.port && ":" + location.port) + "/"; export default class PurchaseOrderStore { - purchaseOrder; - commonStore; - @observable validationErrors; - @observable editMode = false; - @observable purchaseOrderStatus; + purchaseOrder: PurchaseOrder; + commonStore: CommonStore; + validationErrors: string[] = []; + editMode = false; + purchaseOrderStatus: string = ""; + + RTotal = 0; + GTotal = 0; + TTotal = 0; - constructor(purchId: any) { + constructor(purchId: number) { this.commonStore = new CommonStore(); this.purchaseOrder = new PurchaseOrder(); extendObservable(this.purchaseOrder, { @@ -32,11 +35,20 @@ export default class PurchaseOrderStore { purchaseOrderLines: [] }); + makeObservable(this, { + validationErrors: observable, + editMode: observable, + purchaseOrderStatus: observable, + RTotal: observable, + GTotal: observable, + TTotal: observable, + }); + autorun(() => this.computeTotals()); if (purchId !== undefined) { - axios.get(Config.apiUrl + "purchasing/purchaseorder?id=" + purchId) - .then(function (result) { + axios.get(Config.API_URL + "purchasing/purchaseorder?id=" + purchId) + .then((result) => { this.purchaseOrder.id = result.data.id; this.purchaseOrder.paymentTermId = result.data.paymentTermId; this.purchaseOrder.referenceNo = result.data.referenceNo; @@ -44,102 +56,109 @@ export default class PurchaseOrderStore { this.changedVendor(result.data.vendorId); this.getPurchaseOrderStatus(result.data.statusId); this.purchaseOrder.orderDate = result.data.orderDate; - for (var i = 0; i < result.data.purchaseOrderLines.length; i++) { + for (let i = 0; i < result.data.purchaseOrderLines.length; i++) { this.addLineItem( result.data.purchaseOrderLines[i].id, result.data.purchaseOrderLines[i].itemId, result.data.purchaseOrderLines[i].measurementId, result.data.purchaseOrderLines[i].quantity, result.data.purchaseOrderLines[i].amount, - result.data.purchaseOrderLines[i].discount + result.data.purchaseOrderLines[i].discount, + result.data.purchaseOrderLines[i].code // Add the missing argument ); - this.updateLineItem(i, 'code', this.changeItemCode(result.data.purchaseOrderLines[i].itemId)); + this.updateLineItem(i, 'code', Number(this.changeItemCode(result.data.purchaseOrderLines[i].itemId))); } this.computeTotals(); - var nodes = document.getElementById("divPurchaseOrderForm").getElementsByTagName('*'); - for (var i = 0; i < nodes.length; i++) { + const nodes = document.getElementById("divPurchaseOrderForm")?.getElementsByTagName('*'); + for (let i = 0; nodes && i < nodes.length; i++) { nodes[i].className += " disabledControl"; } - }.bind(this)) - .catch(function (error) { - }.bind(this)); + }) + .catch(() => { + }); } else { this.changedEditMode(true); } } - @observable RTotal = 0; - @observable GTotal = 0; - @observable TTotal = 0; + changeItemCode(itemId: string) { + for (let x = 0; x < this.commonStore.items.length; x++) { + const item = this.commonStore.items[x] as PurchaseOrderLine + if (item.id === parseInt(itemId)) { + return item.code; + } + } + } computeTotals() { - var rtotal = 0; - var ttotal = 0; - var gtotal = 0; + let rtotal = 0; + let ttotal = 0; - for (var i = 0; i < this.purchaseOrder.purchaseOrderLines.length; i++) { - var lineItem = this.purchaseOrder.purchaseOrderLines[i]; + for (let i = 0; i < this.purchaseOrder.purchaseOrderLines.length; i++) { + const lineItem = this.purchaseOrder.purchaseOrderLines[i]; rtotal = rtotal + this.getLineTotal(i); - axios.get(Config.apiUrl + "tax/gettax?itemId=" + lineItem.itemId + "&partyId=" + this.purchaseOrder.vendorId + "&type=2") - .then(function (result) { + axios.get(Config.API_URL + "tax/gettax?itemId=" + lineItem.itemId + "&partyId=" + this.purchaseOrder.vendorId + "&type=2") + .then((result) => { if (result.data.length > 0) { ttotal = ttotal + this.commonStore.getPurhcaseLineTaxAmount(lineItem.quantity, lineItem.amount, lineItem.discount, result.data); } this.TTotal = ttotal; this.GTotal = rtotal + ttotal; - }.bind(this)); + }); this.RTotal = rtotal; } } savePurchaseOrder() { - if (this.purchaseOrder.orderDate === undefined) - this.purchaseOrder.orderDate = new Date(Date.now()).toISOString().substring(0, 10); + this.purchaseOrder.orderDate = new Date(new Date(Date.now()).toISOString().substring(0, 10)); if (this.validation() && this.validationErrors.length === 0) { - axios.post(Config.apiUrl + "purchasing/savepurchaseorder", JSON.stringify(this.purchaseOrder), + axios.post(Config.API_URL + "purchasing/savepurchaseorder", JSON.stringify(this.purchaseOrder), { headers: { 'Content-type': 'application/json' } }) - .then(function (response) { + .then(() => { window.location.href = baseUrl + 'purchasing/purchaseorders'; }) - .catch(function (error) { - error.data.map(function (err) { - this.validationErrors.push(err); - }.bind(this)); - }.bind(this)) + .catch((error) => { + if (axios.isAxiosError(error)) { + this.validationErrors.push(`Status: ${error.status} - Message: ${error.response?.data}`); + } else { + console.error(error); + this.validationErrors.push(`Error: ${error}`); + } + }) } } validation() { this.validationErrors = []; - if (this.purchaseOrder.vendorId === undefined || this.purchaseOrder.vendorId === "") + if (this.purchaseOrder.vendorId === undefined || this.purchaseOrder.vendorId.toString() === "") this.validationErrors.push("Vendor is required."); - if (this.purchaseOrder.paymentTermId === undefined || this.purchaseOrder.paymentTermId === "") + if (this.purchaseOrder.paymentTermId === undefined || this.purchaseOrder.paymentTermId.toString() === "") this.validationErrors.push("Payment term is required."); - if (this.purchaseOrder.orderDate === undefined || this.purchaseOrder.orderDate === "") + if (this.purchaseOrder.orderDate === undefined || this.purchaseOrder.orderDate.toString() === "") this.validationErrors.push("Date is required."); if (this.purchaseOrder.purchaseOrderLines === undefined || this.purchaseOrder.purchaseOrderLines.length < 1) this.validationErrors.push("Enter at least 1 line item."); if (this.purchaseOrder.purchaseOrderLines !== undefined && this.purchaseOrder.purchaseOrderLines.length > 0) { - for (var i = 0; i < this.purchaseOrder.purchaseOrderLines.length; i++) { + for (let i = 0; i < this.purchaseOrder.purchaseOrderLines.length; i++) { if (this.purchaseOrder.purchaseOrderLines[i].itemId === undefined - || this.purchaseOrder.purchaseOrderLines[i].itemId === "") + || this.purchaseOrder.purchaseOrderLines[i].itemId.toString() === "") this.validationErrors.push("Item is required."); if (this.purchaseOrder.purchaseOrderLines[i].measurementId === undefined - || this.purchaseOrder.purchaseOrderLines[i].measurementId === "") + || this.purchaseOrder.purchaseOrderLines[i].measurementId.toString() === "") this.validationErrors.push("Uom is required."); if (this.purchaseOrder.purchaseOrderLines[i].quantity === undefined - || this.purchaseOrder.purchaseOrderLines[i].quantity === "" + || this.purchaseOrder.purchaseOrderLines[i].quantity.toString() === "" || this.purchaseOrder.purchaseOrderLines[i].quantity === 0) this.validationErrors.push("Quantity is required."); if (this.purchaseOrder.purchaseOrderLines[i].amount === undefined - || this.purchaseOrder.purchaseOrderLines[i].amount === "" + || this.purchaseOrder.purchaseOrderLines[i].amount.toString() === "" || this.purchaseOrder.purchaseOrderLines[i].amount === 0) this.validationErrors.push("Amount is required."); if (this.getLineTotal(i) === undefined @@ -155,7 +174,7 @@ export default class PurchaseOrderStore { validationLine() { this.validationErrors = []; if (this.purchaseOrder.purchaseOrderLines !== undefined && this.purchaseOrder.purchaseOrderLines.length > 0) { - for (var i = 0; i < this.purchaseOrder.purchaseOrderLines.length; i++) { + for (let i = 0; i < this.purchaseOrder.purchaseOrderLines.length; i++) { if (this.purchaseOrder.purchaseOrderLines[i].itemId === undefined) this.validationErrors.push("Item is required."); if (this.purchaseOrder.purchaseOrderLines[i].measurementId === undefined) @@ -170,12 +189,10 @@ export default class PurchaseOrderStore { } } else { - var itemId, measurementId, quantity, amount, discount; - itemId = (document.getElementById("optNewItemId") as HTMLInputElement).value; - measurementId = (document.getElementById("optNewMeasurementId") as HTMLInputElement).value; - quantity = (document.getElementById("txtNewQuantity") as HTMLInputElement).value; - amount = (document.getElementById("txtNewAmount") as HTMLInputElement).value; - discount = (document.getElementById("txtNewDiscount") as HTMLInputElement).value; + const itemId: string = (document.getElementById("optNewItemId") as HTMLInputElement).value; + const measurementId: string = (document.getElementById("optNewMeasurementId") as HTMLInputElement).value; + const quantity: string = (document.getElementById("txtNewQuantity") as HTMLInputElement).value; + const amount: string = (document.getElementById("txtNewAmount") as HTMLInputElement).value; if (itemId == "" || itemId === undefined) this.validationErrors.push("Item is required."); @@ -188,13 +205,12 @@ export default class PurchaseOrderStore { } if (document.getElementById("optNewItemId")) { - var itemId, measurementId, quantity, amount, discount; - itemId = (document.getElementById("optNewItemId") as HTMLInputElement).value; - measurementId = (document.getElementById("optNewMeasurementId") as HTMLInputElement).value; - quantity = (document.getElementById("txtNewQuantity") as HTMLInputElement).value; - amount = (document.getElementById("txtNewAmount") as HTMLInputElement).value; - discount = (document.getElementById("txtNewDiscount") as HTMLInputElement).value; + const itemId: string = (document.getElementById("optNewItemId") as HTMLInputElement).value; + const measurementId: string = (document.getElementById("optNewMeasurementId") as HTMLInputElement).value; + const quantity: string = (document.getElementById("txtNewQuantity") as HTMLInputElement).value; + const amount: string = (document.getElementById("txtNewAmount") as HTMLInputElement).value; + if (itemId == "" || itemId === undefined) this.validationErrors.push("Item is required."); if (measurementId == "" || measurementId === undefined) @@ -209,50 +225,58 @@ export default class PurchaseOrderStore { return this.validationErrors.length === 0; } - changedReferenceNo(refNo) { + changedReferenceNo(refNo: string) { this.purchaseOrder.referenceNo = refNo; } - changedVendor(vendorId) { + + changedVendor(vendorId: number) { this.purchaseOrder.vendorId = vendorId; } - changedPaymentTerm(paymentTermId) { + changedPaymentTerm(paymentTermId: number) { this.purchaseOrder.paymentTermId = paymentTermId; } - changedOrderDate(date) { + changedOrderDate(date: Date) { this.purchaseOrder.orderDate = date; } - addLineItem(id, itemId, measurementId, quantity, amount, discount, code) { - var newLineItem = new PurchaseOrderLine(id, itemId, measurementId, quantity, amount, discount, code); + addLineItem(id: number, itemId: number, measurementId: number, quantity: number, amount: number, discount: number, code: string) { + const newLineItem = new PurchaseOrderLine(id, itemId, measurementId, quantity, amount, discount, code); this.purchaseOrder.purchaseOrderLines.push(extendObservable(newLineItem, newLineItem)); } - removeLineItem(row) { + removeLineItem(row: number) { this.purchaseOrder.purchaseOrderLines.splice(row, 1); } - updateLineItem(row, targetProperty, value) { + updateLineItem(row: number, targetProperty: keyof PurchaseOrderLine, value: string | number) { if (this.purchaseOrder.purchaseOrderLines.length > 0) - this.purchaseOrder.purchaseOrderLines[row][targetProperty] = value; + (this.purchaseOrder.purchaseOrderLines[row] as Record)[targetProperty] = value; this.computeTotals(); } - getLineTotal(row) { + // updateLineItem(row: number, targetProperty: keyof PurchaseInvoiceLine, value: string | number) { + // if (this.purchaseInvoice.purchaseInvoiceLines.length > 0) + // (this.purchaseInvoice.purchaseInvoiceLines[row] as Record)[targetProperty] = value; + + // this.computeTotals(); + // } + + getLineTotal(row: number) { let lineSum = 0; - let lineItem = this.purchaseOrder.purchaseOrderLines[row]; + const lineItem = this.purchaseOrder.purchaseOrderLines[row]; lineSum = (lineItem.quantity * lineItem.amount) - lineItem.discount; return lineSum; } - changedEditMode(editMode) { + changedEditMode(editMode: boolean) { this.editMode = editMode; } - getPurchaseOrderStatus(statusId) { - var status = ""; + getPurchaseOrderStatus(statusId: number) { + let status = ""; if (statusId === 0) status = "Draft"; else if (statusId === 1) @@ -268,12 +292,5 @@ export default class PurchaseOrderStore { this.purchaseOrderStatus = status; } - changeItemCode(itemId) { - for (var x = 0; x < this.commonStore.items.length; x++) { - if (this.commonStore.items[x].id === parseInt(itemId)) { - return this.commonStore.items[x].code; - } - } - } } \ No newline at end of file diff --git a/src/GoodBooksReact/src/components/Shared/Stores/Quotations/SalesQuotation.tsx b/src/GoodBooksReact/src/components/Shared/Stores/Quotations/SalesQuotation.tsx new file mode 100644 index 000000000..f94ad3dfd --- /dev/null +++ b/src/GoodBooksReact/src/components/Shared/Stores/Quotations/SalesQuotation.tsx @@ -0,0 +1,11 @@ +import SalesQuotationLine from "./SalesQuotationLine"; + +export default class SalesQuotation { + id: number = 0; + customerId: number = 0; + quotationDate: Date = new Date(); + paymentTermId: number = 0; + referenceNo: string = ""; + statusId: number = 0; + salesQuotationLines: SalesQuotationLine[] = []; +} \ No newline at end of file diff --git a/src/GoodBooksReact/src/components/Shared/Stores/Quotations/SalesQuotationLine.tsx b/src/GoodBooksReact/src/components/Shared/Stores/Quotations/SalesQuotationLine.tsx new file mode 100644 index 000000000..5fb6d3f26 --- /dev/null +++ b/src/GoodBooksReact/src/components/Shared/Stores/Quotations/SalesQuotationLine.tsx @@ -0,0 +1,21 @@ +export default class SalesQuotationLine { + id: number = 0; + itemId: number = 0; + measurementId: number = 0; + quantity: number = 0; + amount: number = 0; + discount: number = 0; + code: number = 0; + + constructor(id: number, itemId: number, measurementId: number, + quantity: number, amount: number, discount: number, code: number) { + + this.id = id; + this.itemId = itemId; + this.measurementId = measurementId; + this.quantity = quantity; + this.amount = amount; + this.discount = discount; + this.code = code; + } +} \ No newline at end of file diff --git a/src/AccountGoWeb/Scripts/Shared/Stores/Quotations/SalesQuotationStore.tsx b/src/GoodBooksReact/src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx similarity index 58% rename from src/AccountGoWeb/Scripts/Shared/Stores/Quotations/SalesQuotationStore.tsx rename to src/GoodBooksReact/src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx index 160ab2c09..ca9288c1e 100644 --- a/src/AccountGoWeb/Scripts/Shared/Stores/Quotations/SalesQuotationStore.tsx +++ b/src/GoodBooksReact/src/components/Shared/Stores/Quotations/SalesQuotationStore.tsx @@ -1,27 +1,29 @@ -import {observable, extendObservable, action, autorun, computed} from 'mobx'; -import * as axios from "axios"; -import * as d3 from "d3"; - -import Config = require("Config"); +import {observable, extendObservable, autorun, makeObservable} from 'mobx'; +import axios from "axios"; +import Config from '../../Config'; import SalesQuotation from './SalesQuotation'; import SalesQuotationLine from './SalesQuotationLine'; import CommonStore from "../Common/CommonStore"; -let baseUrl = location.protocol +const baseUrl = location.protocol + "//" + location.hostname + (location.port && ":" + location.port) + "/"; export default class SalesQuotationStore { - salesQuotation; - commonStore; - @observable salesQuotationStatus; - @observable validationErrors; - @observable editMode = false; - - constructor(quotationId) { + salesQuotation: SalesQuotation; + commonStore: CommonStore; + salesQuotationStatus: string = ""; + validationErrors: string[] = []; + editMode = false; + + RTotal = 0; + GTotal = 0; + TTotal = 0; + + constructor(quotationId: number) { this.commonStore = new CommonStore(); this.salesQuotation = new SalesQuotation(); extendObservable(this.salesQuotation, { @@ -33,13 +35,20 @@ export default class SalesQuotationStore { salesQuotationLines: [] }); - + makeObservable(this, { + validationErrors: observable, + salesQuotationStatus: observable, + editMode: observable, + RTotal: observable, + GTotal: observable, + TTotal: observable, + }); autorun(() => this.computeTotals()); if (quotationId !== undefined) { - var result = axios.get(Config.apiUrl + "sales/quotation?id=" + quotationId); - result.then(function (result) { + const result = axios.get(Config.API_URL + "sales/quotation?id=" + quotationId); + result.then((result) => { this.salesQuotation.id = result.data.id; this.salesQuotation.paymentTermId = result.data.paymentTermId; this.salesQuotation.referenceNo = result.data.referenceNo; @@ -47,66 +56,56 @@ export default class SalesQuotationStore { this.changedCustomer(result.data.customerId); this.getQuotationStatus(result.data.statusId); this.changedQuotationDate(result.data.quotationDate); - for (var i = 0; i < result.data.salesQuotationLines.length; i++) { + for (let i = 0; i < result.data.salesQuotationLines.length; i++) { this.addLineItem( result.data.salesQuotationLines[i].id, result.data.salesQuotationLines[i].itemId, result.data.salesQuotationLines[i].measurementId, result.data.salesQuotationLines[i].quantity, result.data.salesQuotationLines[i].amount, - result.data.salesQuotationLines[i].discount - + result.data.salesQuotationLines[i].discount, + result.data.salesQuotationLines[i].code ); - this.updateLineItem(i, 'code', this.changeItemCode(result.data.salesQuotationLines[i].itemId)); + this.updateLineItem(i, 'code', Number(this.changeItemCode(result.data.salesQuotationLines[i].itemId))); } this.computeTotals(); - var nodes = document.getElementById("divSalesQuotationForm").getElementsByTagName('*'); - for (var i = 0; i < nodes.length; i++) { + const nodes = document.getElementById("divSalesQuotationForm")?.getElementsByTagName('*'); + for (let i = 0; nodes && i < nodes.length; i++) { nodes[i].className += " disabledControl"; } - }.bind(this)); + }); } else { this.changedEditMode(true); } - } - @observable RTotal = 0; - @observable GTotal = 0; - @observable TTotal = 0; - - - - computeTotals() { - var rtotal = 0; - var ttotal = 0; - var gtotal = 0; + let rtotal = 0; + let ttotal = 0; - for (var i = 0; i < this.salesQuotation.salesQuotationLines.length; i++) { - var lineItem = this.salesQuotation.salesQuotationLines[i]; + for (let i = 0; i < this.salesQuotation.salesQuotationLines.length; i++) { + const lineItem = this.salesQuotation.salesQuotationLines[i]; rtotal = rtotal + this.getLineTotal(i); - axios.get(Config.apiUrl + "tax/gettax?itemId=" + lineItem.itemId + "&partyId=" + this.salesQuotation.customerId + "&type=1") - .then(function (result) { + axios.get(Config.API_URL + "tax/gettax?itemId=" + lineItem.itemId + "&partyId=" + this.salesQuotation.customerId + "&type=1") + .then((result) => { if (result.data.length > 0) { ttotal = ttotal + this.commonStore.getSalesLineTaxAmount(lineItem.quantity, lineItem.amount, lineItem.discount, result.data); } this.TTotal = ttotal; this.GTotal = rtotal + ttotal; - }.bind(this)); + }); this.RTotal = rtotal; } } saveNewQuotation() { - if (this.salesQuotation.quotationDate === undefined) - this.salesQuotation.quotationDate = new Date(Date.now()).toISOString().substring(0, 10); + this.salesQuotation.quotationDate = new Date(new Date(Date.now()).toISOString().substring(0, 10)); if (this.validation()) { if (this.validationErrors.length === 0) { - axios.post(Config.apiUrl + "sales/savequotation", JSON.stringify(this.salesQuotation), + axios.post(Config.API_URL + "sales/savequotation", JSON.stringify(this.salesQuotation), { headers: { @@ -114,23 +113,25 @@ export default class SalesQuotationStore { } } ) - .then(function (response) { + .then(() => { window.location.href = baseUrl + 'quotations'; }) - .catch(function (error) { - error.data.map(function (err) { - this.validationErrors.push(err); - }.bind(this)); - }.bind(this)); + .catch((error) => { + if (axios.isAxiosError(error)) { + this.validationErrors.push(`Status: ${error.status} - Message: ${error.response?.data}`); + } else { + console.error(error); + this.validationErrors.push(`Error: ${error}`); + } + }) } } } bookQuotation() { - if (this.validation()) { if (this.validationErrors.length === 0) { - axios.post(Config.apiUrl + "sales/bookquotation?id=" + parseInt(this.salesQuotation.id), + axios.post(Config.API_URL + "sales/bookquotation?id=" + String(this.salesQuotation.id), { headers: { @@ -138,14 +139,17 @@ export default class SalesQuotationStore { } } ) - .then(function (response) { + .then(() => { window.location.href = baseUrl + 'quotations'; }) - .catch(function (error) { - error.data.map(function (err) { - this.validationErrors.push(err); - }.bind(this)); - }.bind(this)); + .catch((error) => { + if (axios.isAxiosError(error)) { + this.validationErrors.push(`Status: ${error.status} - Message: ${error.response?.data}`); + } else { + console.error(error); + this.validationErrors.push(`Error: ${error}`); + } + }) } } } @@ -161,17 +165,16 @@ export default class SalesQuotationStore { if (this.salesQuotation.salesQuotationLines === undefined || this.salesQuotation.salesQuotationLines.length < 1) this.validationErrors.push("Enter at least 1 line item."); if (this.salesQuotation.salesQuotationLines !== undefined && this.salesQuotation.salesQuotationLines.length > 0) { - for (var i = 0; i < this.salesQuotation.salesQuotationLines.length; i++) { - if (this.salesQuotation.salesQuotationLines[i].itemId === undefined || this.salesQuotation.salesQuotationLines[i].itemId === "") + for (let i = 0; i < this.salesQuotation.salesQuotationLines.length; i++) { + if (typeof this.salesQuotation.salesQuotationLines[i].itemId !== 'number' || isNaN(this.salesQuotation.salesQuotationLines[i].itemId)) this.validationErrors.push("Item is required."); - if (this.salesQuotation.salesQuotationLines[i].measurementId === undefined || this.salesQuotation.salesQuotationLines[i].measurementId === "") + if (typeof this.salesQuotation.salesQuotationLines[i].measurementId !== 'number' || isNaN(this.salesQuotation.salesQuotationLines[i].measurementId)) this.validationErrors.push("Uom is required."); - if (this.salesQuotation.salesQuotationLines[i].quantity === undefined || this.salesQuotation.salesQuotationLines[i].quantity === "") + if (typeof this.salesQuotation.salesQuotationLines[i].quantity !== 'number' || isNaN(this.salesQuotation.salesQuotationLines[i].quantity)) this.validationErrors.push("Quantity is required."); - if (this.salesQuotation.salesQuotationLines[i].amount === undefined || this.salesQuotation.salesQuotationLines[i].amount === "") + if (typeof this.salesQuotation.salesQuotationLines[i].amount !== 'number' || isNaN(this.salesQuotation.salesQuotationLines[i].amount)) this.validationErrors.push("Amount is required."); - if (this.getLineTotal(i) === undefined - || this.getLineTotal(i).toString() === "NaN") + if (this.getLineTotal(i) === undefined || isNaN(this.getLineTotal(i))) this.validationErrors.push("Invalid data."); } } @@ -180,8 +183,8 @@ export default class SalesQuotationStore { } - getQuotationStatus(statusId) { - var status = ""; + getQuotationStatus(statusId: number) { + let status = ""; if (statusId === 0) status = "Draft"; else if (statusId === 1) @@ -204,7 +207,7 @@ export default class SalesQuotationStore { validationLine() { this.validationErrors = []; if (this.salesQuotation.salesQuotationLines !== undefined && this.salesQuotation.salesQuotationLines.length > 0) { - for (var i = 0; i < this.salesQuotation.salesQuotationLines.length; i++) { + for (let i = 0; i < this.salesQuotation.salesQuotationLines.length; i++) { if (this.salesQuotation.salesQuotationLines[i].itemId === undefined) this.validationErrors.push("Item is required."); if (this.salesQuotation.salesQuotationLines[i].measurementId === undefined) @@ -219,12 +222,10 @@ export default class SalesQuotationStore { } } else { - var itemId, measurementId, quantity, amount, discount; - itemId = (document.getElementById("optNewItemId") as HTMLInputElement).value; - measurementId = (document.getElementById("optNewMeasurementId") as HTMLInputElement).value; - quantity = (document.getElementById("txtNewQuantity") as HTMLInputElement).value; - amount = (document.getElementById("txtNewAmount") as HTMLInputElement).value; - discount = (document.getElementById("txtNewDiscount") as HTMLInputElement).value; + const itemId: string = (document.getElementById("optNewItemId") as HTMLInputElement).value; + const measurementId: string = (document.getElementById("optNewMeasurementId") as HTMLInputElement).value; + const quantity: string = (document.getElementById("txtNewQuantity") as HTMLInputElement).value; + const amount: string = (document.getElementById("txtNewAmount") as HTMLInputElement).value; if (itemId == "" || itemId === undefined) this.validationErrors.push("Item is required."); @@ -237,12 +238,10 @@ export default class SalesQuotationStore { } if (document.getElementById("optNewItemId")) { - var itemId, measurementId, quantity, amount, discount; - itemId = (document.getElementById("optNewItemId") as HTMLInputElement).value; - measurementId = (document.getElementById("optNewMeasurementId") as HTMLInputElement).value; - quantity = (document.getElementById("txtNewQuantity") as HTMLInputElement).value; - amount = (document.getElementById("txtNewAmount") as HTMLInputElement).value; - discount = (document.getElementById("txtNewDiscount") as HTMLInputElement).value; + const itemId: string = (document.getElementById("optNewItemId") as HTMLInputElement).value; + const measurementId: string = (document.getElementById("optNewMeasurementId") as HTMLInputElement).value; + const quantity: string = (document.getElementById("txtNewQuantity") as HTMLInputElement).value; + const amount: string = (document.getElementById("txtNewAmount") as HTMLInputElement).value; if (itemId == "" || itemId === undefined) this.validationErrors.push("Item is required."); @@ -258,57 +257,62 @@ export default class SalesQuotationStore { return this.validationErrors.length === 0; } - changedCustomer(custId) { + changedCustomer(custId: number) { this.salesQuotation.customerId = custId; } - changedPaymentTerm(termId) { + changedPaymentTerm(termId: number) { this.salesQuotation.paymentTermId = termId; } - changedQuotationDate(date) { + changedQuotationDate(date: Date) { this.salesQuotation.quotationDate = date; } - changedReferenceNo(refNo) { + changedReferenceNo(refNo: string) { this.salesQuotation.referenceNo = refNo; } - changedQuoteStatus(statusId) { + changedQuoteStatus(statusId: number) { this.salesQuotation.statusId = statusId; } - changeItemCode(itemId) { + changeItemCode(itemId: number) { - for (var x = 0; x < this.commonStore.items.length; x++) { - if (this.commonStore.items[x].id === parseInt(itemId)) { - return this.commonStore.items[x].code; + for (let x = 0; x < this.commonStore.items.length; x++) { + const lineItewm = this.commonStore.items[x] as SalesQuotationLine; + if (lineItewm.id === itemId) { + return lineItewm.code; } } } - addLineItem(id, itemId, measurementId, quantity, amount, discount, code) { - var newLineItem = new SalesQuotationLine(id, itemId, measurementId, quantity, amount, discount, code); + addLineItem(id: number, itemId: number, measurementId: number, + quantity: number, amount: number, discount: number, code: number) { + + const newLineItem = new SalesQuotationLine(id, itemId, measurementId, quantity, amount, discount, code); this.salesQuotation.salesQuotationLines.push(extendObservable(newLineItem, newLineItem)); } - removeLineItem(row) { + removeLineItem(row: number) { this.salesQuotation.salesQuotationLines.splice(row, 1); } - updateLineItem(row, targetProperty, value) { - //if (this.salesQuotation.salesQuotationLines.length > 0) - this.salesQuotation.salesQuotationLines[row][targetProperty] = value; + updateLineItem(row: number, targetProperty: keyof SalesQuotationLine, value: string | number) { + + if (this.salesQuotation.salesQuotationLines.length > 0) + (this.salesQuotation.salesQuotationLines[row] as Record)[targetProperty] = value; + this.computeTotals(); } - getLineTotal(row) { + getLineTotal(row: number) { let lineSum = 0; - let lineItem = this.salesQuotation.salesQuotationLines[row]; + const lineItem = this.salesQuotation.salesQuotationLines[row]; lineSum = (lineItem.quantity * lineItem.amount) - lineItem.discount; return lineSum; } - changedEditMode(editMode) { + changedEditMode(editMode: boolean) { this.editMode = editMode; } diff --git a/src/AccountGoWeb/Scripts/Shared/Stores/Sales/SalesInvoice.tsx b/src/GoodBooksReact/src/components/Shared/Stores/Sales/SalesInvoice.tsx similarity index 67% rename from src/AccountGoWeb/Scripts/Shared/Stores/Sales/SalesInvoice.tsx rename to src/GoodBooksReact/src/components/Shared/Stores/Sales/SalesInvoice.tsx index 9d2e92614..914026024 100644 --- a/src/AccountGoWeb/Scripts/Shared/Stores/Sales/SalesInvoice.tsx +++ b/src/GoodBooksReact/src/components/Shared/Stores/Sales/SalesInvoice.tsx @@ -2,11 +2,11 @@ export default class SalesInvoice { id: number; - fromSalesOrderId: any; - customerId: number; - invoiceDate: Date; - paymentTermId: number; - referenceNo: string; + fromSalesOrderId: number = 0; + customerId: number = 0; + invoiceDate: Date = new Date(); + paymentTermId: number = 0; + referenceNo: string= ""; posted: boolean; readyForPosting: boolean; salesInvoiceLines: SalesInvoiceLine[] = []; diff --git a/src/GoodBooksReact/src/components/Shared/Stores/Sales/SalesInvoiceLine.tsx b/src/GoodBooksReact/src/components/Shared/Stores/Sales/SalesInvoiceLine.tsx new file mode 100644 index 000000000..8a0b3cbdc --- /dev/null +++ b/src/GoodBooksReact/src/components/Shared/Stores/Sales/SalesInvoiceLine.tsx @@ -0,0 +1,21 @@ +export default class SalesInvoiceLine { + id: number = 0; + itemId: number = 0; + measurementId: number = 0; + quantity: number = 0; + amount: number = 0; + discount: number = 0; + remainingQtyToInvoice: number = 0; + code: string = ""; + + constructor(id: number, itemId: number, measurementId: number, quantity: number, amount: number, discount: number, code: string) { + this.id = id; + this.itemId = itemId; + this.measurementId = measurementId; + this.quantity = quantity; + this.amount = amount; + this.discount = discount; + this.remainingQtyToInvoice = quantity; + this.code = code; + } +} \ No newline at end of file diff --git a/src/AccountGoWeb/Scripts/Shared/Stores/Sales/SalesInvoiceStore.tsx b/src/GoodBooksReact/src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx similarity index 64% rename from src/AccountGoWeb/Scripts/Shared/Stores/Sales/SalesInvoiceStore.tsx rename to src/GoodBooksReact/src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx index 8fcf73db0..480b710e5 100644 --- a/src/AccountGoWeb/Scripts/Shared/Stores/Sales/SalesInvoiceStore.tsx +++ b/src/GoodBooksReact/src/components/Shared/Stores/Sales/SalesInvoiceStore.tsx @@ -1,14 +1,12 @@ -import {observable, extendObservable, action, autorun, computed} from 'mobx'; -import * as axios from "axios"; - -import Config = require("Config"); +import {observable, extendObservable, autorun, makeObservable} from 'mobx'; +import axios from "axios"; +import Config from '../../Config'; import SalesInvoice from './SalesInvoice'; import SalesInvoiceLine from './SalesInvoiceLine'; - import CommonStore from "../Common/CommonStore"; -let baseUrl = location.protocol +const baseUrl = location.protocol + "//" + location.hostname + (location.port && ":" + location.port) + "/"; @@ -16,11 +14,14 @@ let baseUrl = location.protocol export default class SalesStore { salesInvoice; commonStore; - @observable validationErrors; - @observable editMode = false; - - - constructor(orderId, invoiceId) { + validationErrors: string[] = []; + editMode = false; + + RTotal = 0; + GTotal = 0; + TTotal = 0; + + constructor(orderId: number, invoiceId: number) { this.commonStore = new CommonStore(); this.salesInvoice = new SalesInvoice(); extendObservable(this.salesInvoice, { @@ -33,14 +34,21 @@ export default class SalesStore { salesInvoiceLines: [] }); + makeObservable(this, { + validationErrors: observable, + editMode: observable, + RTotal: observable, + GTotal: observable, + TTotal: observable, + }); autorun(() => this.computeTotals()); if (orderId !== undefined) { - var result = axios.get(Config.apiUrl + "sales/salesorder?id=" + orderId); - result.then(function(result) { + const result = axios.get(Config.API_URL + "sales/salesorder?id=" + orderId); + result.then((result) => { - for (var i = 0; i < result.data.salesOrderLines.length; i++) { + for (let i = 0; i < result.data.salesOrderLines.length; i++) { if (result.data.salesOrderLines[i].remainingQtyToInvoice == 0) continue; this.addLineItem( @@ -49,7 +57,8 @@ export default class SalesStore { result.data.salesOrderLines[i].measurementId, result.data.salesOrderLines[i].remainingQtyToInvoice, result.data.salesOrderLines[i].amount, - result.data.salesOrderLines[i].discount + result.data.salesOrderLines[i].discount, + result.data.salesOrderLines[i].code ); } this.salesInvoice.fromSalesOrderId = orderId; @@ -60,20 +69,21 @@ export default class SalesStore { this.computeTotals(); this.changedEditMode(true); - }.bind(this)); + }); } else if (invoiceId !== undefined) { - var result = axios.get(Config.apiUrl + "sales/salesinvoice?id=" + invoiceId); - result.then(function(result) { - for (var i = 0; i < result.data.salesInvoiceLines.length; i++) { + const result = axios.get(Config.API_URL + "sales/salesinvoice?id=" + invoiceId); + result.then((result) => { + for (let i = 0; i < result.data.salesInvoiceLines.length; i++) { this.addLineItem( result.data.salesInvoiceLines[i].id, result.data.salesInvoiceLines[i].itemId, result.data.salesInvoiceLines[i].measurementId, result.data.salesInvoiceLines[i].quantity, result.data.salesInvoiceLines[i].amount, - result.data.salesInvoiceLines[i].discount + result.data.salesInvoiceLines[i].discount, + result.data.salesInvoiceLines[i].code ); - this.updateLineItem(i, 'code', this.changeItemCode(result.data.salesInvoiceLines[i].itemId)); + this.updateLineItem(i, 'code', this.changeItemCode(result.data.salesInvoiceLines[i].itemId)!); } this.salesInvoice.id = result.data.id; @@ -85,37 +95,31 @@ export default class SalesStore { this.salesInvoice.readyForPosting = result.data.readyForPosting; this.computeTotals(); - var nodes = document.getElementById("divSalesInvoiceForm").getElementsByTagName('*'); - for (var i = 0; i < nodes.length; i++) { + const nodes = document.getElementById("divSalesInvoiceForm")!.getElementsByTagName('*'); + for (let i = 0; i < nodes.length; i++) { nodes[i].className += " disabledControl"; } - }.bind(this)); + }); } else this.changedEditMode(true); } - - @observable RTotal = 0; - @observable GTotal = 0; - @observable TTotal = 0; - computeTotals() { - var rtotal = 0; - var ttotal = 0; - var gtotal = 0; + let rtotal = 0; + let ttotal = 0; - for (var i = 0; i < this.salesInvoice.salesInvoiceLines.length; i++) { - var lineItem = this.salesInvoice.salesInvoiceLines[i]; + for (let i = 0; i < this.salesInvoice.salesInvoiceLines.length; i++) { + const lineItem = this.salesInvoice.salesInvoiceLines[i]; rtotal = rtotal + this.getLineTotal(i); - axios.get(Config.apiUrl + "tax/gettax?itemId=" + lineItem.itemId + "&partyId=" + this.salesInvoice.customerId + "&type=1") - .then(function (result) { + axios.get(Config.API_URL + "tax/gettax?itemId=" + lineItem.itemId + "&partyId=" + this.salesInvoice.customerId + "&type=1") + .then((result) => { if (result.data.length > 0) { ttotal = ttotal + this.commonStore.getSalesLineTaxAmount(lineItem.quantity, lineItem.amount, lineItem.discount, result.data); } this.TTotal = ttotal; this.GTotal = rtotal + ttotal; - }.bind(this)); + }); this.RTotal = rtotal; } } @@ -123,53 +127,59 @@ export default class SalesStore { saveNewSalesInvoice() { if (this.salesInvoice.invoiceDate === undefined) - this.salesInvoice.invoiceDate = new Date(Date.now()).toISOString().substring(0, 10); + this.salesInvoice.invoiceDate = new Date(new Date(Date.now()).toISOString().substring(0, 10)); if (this.validation() && this.validationErrors.length === 0) { - axios.post(Config.apiUrl + "sales/savesalesinvoice", JSON.stringify(this.salesInvoice), + axios.post(Config.API_URL + "sales/savesalesinvoice", JSON.stringify(this.salesInvoice), { headers: { 'Content-type': 'application/json' } }) - .then(function (response) { + .then(() => { window.location.href = baseUrl + 'sales/salesinvoices'; }) - .catch(function (error) { - error.data.map(function (err) { - this.validationErrors.push(err); - }.bind(this)); - }.bind(this)) + .catch((error) => { + if (axios.isAxiosError(error)) { + this.validationErrors.push(`Status: ${error.status} - Message: ${error.response?.data}`); + } else { + console.error(error); + this.validationErrors.push(`Error: ${error}`); + } + }) } } printInvoice() { - var w = 800; - var h = 600; - var wLeft = window.screenLeft ? window.screenLeft : window.screenX; - var wTop = window.screenTop ? window.screenTop : window.screenY; + const w = 800; + const h = 600; + const wLeft = window.screenLeft ? window.screenLeft : window.screenX; + const wTop = window.screenTop ? window.screenTop : window.screenY; - var left = wLeft + (window.innerWidth / 2) - (w / 2); - var top = wTop + (window.innerHeight / 2) - (h / 2); + const left = wLeft + (window.innerWidth / 2) - (w / 2); + const top = wTop + (window.innerHeight / 2) - (h / 2); window.open(baseUrl + 'sales/salesinvoicepdf?id=' + this.salesInvoice.id, "_blank", 'toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=no, resizable=no, copyhistory=no, width=' + w + ', height=' + h + ', top=' + top + ', left=' + left); } postInvoice() { if (this.validation() && this.validationErrors.length === 0) { - axios.post(Config.apiUrl + "sales/postsalesinvoice", JSON.stringify(this.salesInvoice), + axios.post(Config.API_URL + "sales/postsalesinvoice", JSON.stringify(this.salesInvoice), { headers: { 'Content-type': 'application/json' } }) - .then(function (response) { + .then(() => { window.location.href = baseUrl + 'sales/salesinvoices'; }) - .catch(function (error) { - error.data.map(function (err) { - this.validationErrors.push(err); - }.bind(this)); - }.bind(this)) + .catch((error) => { + if (axios.isAxiosError(error)) { + this.validationErrors.push(`Status: ${error.status} - Message: ${error.response?.data}`); + } else { + console.error(error); + this.validationErrors.push(`Error: ${error}`); + } + }) } } @@ -184,7 +194,7 @@ export default class SalesStore { if (this.salesInvoice.salesInvoiceLines === undefined || this.salesInvoice.salesInvoiceLines.length < 1) this.validationErrors.push("Enter at least 1 line item."); if (this.salesInvoice.salesInvoiceLines !== undefined && this.salesInvoice.salesInvoiceLines.length > 0) { - for (var i = 0; i < this.salesInvoice.salesInvoiceLines.length; i++) { + for (let i = 0; i < this.salesInvoice.salesInvoiceLines.length; i++) { if (this.salesInvoice.salesInvoiceLines[i].itemId === undefined) this.validationErrors.push("Item is required."); if (this.salesInvoice.salesInvoiceLines[i].measurementId === undefined) @@ -208,7 +218,7 @@ export default class SalesStore { validationLine() { this.validationErrors = []; if (this.salesInvoice.salesInvoiceLines !== undefined && this.salesInvoice.salesInvoiceLines.length > 0) { - for (var i = 0; i < this.salesInvoice.salesInvoiceLines.length; i++) { + for (let i = 0; i < this.salesInvoice.salesInvoiceLines.length; i++) { if (this.salesInvoice.salesInvoiceLines[i].itemId === undefined) this.validationErrors.push("Item is required."); if (this.salesInvoice.salesInvoiceLines[i].measurementId === undefined) @@ -223,12 +233,10 @@ export default class SalesStore { } } else { - var itemId, measurementId, quantity, amount, discount; - itemId = (document.getElementById("optNewItemId") as HTMLInputElement).value; - measurementId = (document.getElementById("optNewMeasurementId") as HTMLInputElement).value; - quantity = (document.getElementById("txtNewQuantity") as HTMLInputElement).value; - amount = (document.getElementById("txtNewAmount") as HTMLInputElement).value; - discount = (document.getElementById("txtNewDiscount") as HTMLInputElement).value; + const itemId: string = (document.getElementById("optNewItemId") as HTMLInputElement).value; + const measurementId: string = (document.getElementById("optNewMeasurementId") as HTMLInputElement).value; + const quantity: string = (document.getElementById("txtNewQuantity") as HTMLInputElement).value; + const amount: string = (document.getElementById("txtNewAmount") as HTMLInputElement).value; if (itemId == "" || itemId === undefined) this.validationErrors.push("Item is required."); @@ -241,12 +249,10 @@ export default class SalesStore { } if (document.getElementById("optNewItemId")) { - var itemId, measurementId, quantity, amount, discount; - itemId = (document.getElementById("optNewItemId") as HTMLInputElement).value; - measurementId = (document.getElementById("optNewMeasurementId") as HTMLInputElement).value; - quantity = (document.getElementById("txtNewQuantity") as HTMLInputElement).value; - amount = (document.getElementById("txtNewAmount") as HTMLInputElement).value; - discount = (document.getElementById("txtNewDiscount") as HTMLInputElement).value; + const itemId: string = (document.getElementById("optNewItemId") as HTMLInputElement).value; + const measurementId: string = (document.getElementById("optNewMeasurementId") as HTMLInputElement).value; + const quantity: string = (document.getElementById("txtNewQuantity") as HTMLInputElement).value; + const amount: string = (document.getElementById("txtNewAmount") as HTMLInputElement).value; if (itemId == "" || itemId === undefined) this.validationErrors.push("Item is required."); @@ -263,53 +269,55 @@ export default class SalesStore { } - changedReferenceNo(refNo) { + changedReferenceNo(refNo: string) { this.salesInvoice.referenceNo = refNo; } - changedCustomer(custId) { + + changedCustomer(custId: number) { this.salesInvoice.customerId = custId; } - changedInvoiceDate(date) { + changedInvoiceDate(date: Date) { this.salesInvoice.invoiceDate = date; } - changedPaymentTerm(termId) { + changedPaymentTerm(termId: number) { this.salesInvoice.paymentTermId = termId; } - addLineItem(id, itemId, measurementId, quantity, amount, discount, code) { - var newLineItem = new SalesInvoiceLine(id, itemId, measurementId, quantity, amount, discount, code); + addLineItem(id: number, itemId: number, measurementId: number, quantity: number, amount: number, discount: number, code: string) { + const newLineItem = new SalesInvoiceLine(id, itemId, measurementId, quantity, amount, discount, code); this.salesInvoice.salesInvoiceLines.push(extendObservable(newLineItem, newLineItem)); } - removeLineItem(row) { + removeLineItem(row: number) { this.salesInvoice.salesInvoiceLines.splice(row, 1); } - updateLineItem(row, targetProperty, value) { + updateLineItem(row: number, targetProperty: keyof SalesInvoiceLine, value: string | number) { if (this.salesInvoice.salesInvoiceLines.length > 0) - this.salesInvoice.salesInvoiceLines[row][targetProperty] = value; + (this.salesInvoice.salesInvoiceLines[row] as Record)[targetProperty] = value; this.computeTotals(); } - getLineTotal(row) { + getLineTotal(row: number) { let lineSum = 0; - let lineItem = this.salesInvoice.salesInvoiceLines[row]; + const lineItem = this.salesInvoice.salesInvoiceLines[row]; lineSum = (lineItem.quantity * lineItem.amount) - lineItem.discount; return lineSum; } - changedEditMode(editMode) { + changedEditMode(editMode: boolean) { this.editMode = editMode; } - changeItemCode(itemId) { + changeItemCode(itemId: number) { - for (var x = 0; x < this.commonStore.items.length; x++) { - if (this.commonStore.items[x].id === parseInt(itemId)) { - return this.commonStore.items[x].code; + for (let x = 0; x < this.commonStore.items.length; x++) { + const lineItem = this.commonStore.items[x] as SalesInvoiceLine; + if (lineItem.id === itemId) { + return lineItem.code; } } } diff --git a/src/GoodBooksReact/src/components/Shared/Stores/Sales/SalesOrder.tsx b/src/GoodBooksReact/src/components/Shared/Stores/Sales/SalesOrder.tsx new file mode 100644 index 000000000..5398fb0e8 --- /dev/null +++ b/src/GoodBooksReact/src/components/Shared/Stores/Sales/SalesOrder.tsx @@ -0,0 +1,12 @@ +import SalesOrderLine from "./SalesOrderLine"; + +export default class SalesOrder { + id: number = 0; + customerId: number = 0; + orderDate: Date = new Date(); + paymentTermId: number = 0; + referenceNo: string = ""; + statusId: number = 0; + quotationId: number = 0; + salesOrderLines: SalesOrderLine[] = []; +} \ No newline at end of file diff --git a/src/GoodBooksReact/src/components/Shared/Stores/Sales/SalesOrderLine.tsx b/src/GoodBooksReact/src/components/Shared/Stores/Sales/SalesOrderLine.tsx new file mode 100644 index 000000000..4fdf56719 --- /dev/null +++ b/src/GoodBooksReact/src/components/Shared/Stores/Sales/SalesOrderLine.tsx @@ -0,0 +1,19 @@ +export default class SalesOrderLine { + id: number = 0; + itemId: number = 0; + measurementId: number = 0; + quantity: number = 0; + amount: number = 0; + discount: number = 0; + code: string = ""; + + constructor(id: number, itemId: number, measurementId: number, quantity: number, amount: number, discount: number, code: string) { + this.id = id; + this.itemId = itemId; + this.measurementId = measurementId; + this.quantity = quantity; + this.amount = amount; + this.discount = discount; + this.code = code; + } +} \ No newline at end of file diff --git a/src/AccountGoWeb/Scripts/Shared/Stores/Sales/SalesOrderStore.tsx b/src/GoodBooksReact/src/components/Shared/Stores/Sales/SalesOrderStore.tsx similarity index 66% rename from src/AccountGoWeb/Scripts/Shared/Stores/Sales/SalesOrderStore.tsx rename to src/GoodBooksReact/src/components/Shared/Stores/Sales/SalesOrderStore.tsx index 5cd442fd9..3e9a46f17 100644 --- a/src/AccountGoWeb/Scripts/Shared/Stores/Sales/SalesOrderStore.tsx +++ b/src/GoodBooksReact/src/components/Shared/Stores/Sales/SalesOrderStore.tsx @@ -1,14 +1,13 @@ -import {observable, extendObservable, action, autorun, computed} from 'mobx'; -import * as axios from "axios"; - -import Config = require("Config"); +import {observable, extendObservable, autorun, makeObservable} from 'mobx'; +import axios from "axios"; +import Config from '../../Config'; import SalesOrder from './SalesOrder'; import SalesOrderLine from './SalesOrderLine'; import CommonStore from "../Common/CommonStore"; -let baseUrl = location.protocol +const baseUrl = location.protocol + "//" + location.hostname + (location.port && ":" + location.port) + "/"; @@ -16,12 +15,17 @@ let baseUrl = location.protocol export default class SalesOrderStore { salesOrder; commonStore; - @observable validationErrors; - @observable salesOrderStatus; - @observable salesQuotationStatus; - @observable editMode = false; - @observable hasQuotation = false; - constructor(quotationId, orderId) { + validationErrors: string[] = []; + salesOrderStatus: string = ""; + salesQuotationStatus: string = ""; + editMode = false; + hasQuotation = false; + + RTotal = 0; + GTotal = 0; + TTotal = 0; + + constructor(quotationId: number, orderId: number) { this.commonStore = new CommonStore(); this.salesOrder = new SalesOrder(); extendObservable(this.salesOrder, { @@ -33,11 +37,22 @@ export default class SalesOrderStore { salesOrderLines: [] }); + makeObservable(this, { + validationErrors: observable, + salesOrderStatus: observable, + salesQuotationStatus: observable, + editMode: observable, + hasQuotation: observable, + RTotal: observable, + GTotal: observable, + TTotal: observable, + }); + autorun(() => this.computeTotals()); if (quotationId !== undefined) { - var result = axios.get(Config.apiUrl + "sales/quotation?id=" + quotationId); - result.then(function (result) { + const result = axios.get(Config.API_URL + "sales/quotation?id=" + quotationId); + result.then((result) => { this.changedCustomer(result.data.customerId); this.salesOrder.paymentTermId = result.data.paymentTermId; this.salesOrder.referenceNo = result.data.referenceNo; @@ -46,49 +61,51 @@ export default class SalesOrderStore { this.hasQuotation = true; // this variable will serve as the footprint that it has a quotation and the edit button wil be disable. //for addition to save quotation to set status closed - order created this.salesOrder.quotationId = quotationId; - for (var i = 0; i < result.data.salesQuotationLines.length; i++) { + for (let i = 0; i < result.data.salesQuotationLines.length; i++) { this.addLineItem( result.data.salesQuotationLines[i].id, result.data.salesQuotationLines[i].itemId, result.data.salesQuotationLines[i].measurementId, result.data.salesQuotationLines[i].quantity, result.data.salesQuotationLines[i].amount, - result.data.salesQuotationLines[i].discount + result.data.salesQuotationLines[i].discount, + result.data.salesQuotationLines[i].code ); } this.computeTotals(); - var nodes = document.getElementById("divSalesOrderForm").getElementsByTagName('*'); - for (var i = 0; i < nodes.length; i++) { + const nodes = document.getElementById("divSalesOrderForm")!.getElementsByTagName('*'); + for (let i = 0; i < nodes.length; i++) { nodes[i].className += " disabledControl"; } - }.bind(this)); + }); } else if (orderId !== undefined) { - var result = axios.get(Config.apiUrl + "sales/salesorder?id=" + orderId); - result.then(function (result) { + const result = axios.get(Config.API_URL + "sales/salesorder?id=" + orderId); + result.then((result) => { this.salesOrder.id = result.data.id; this.changedCustomer(result.data.customerId); this.salesOrder.paymentTermId = result.data.paymentTermId; this.salesOrder.referenceNo = result.data.referenceNo; this.changedOrderDate(result.data.orderDate); this.getOrderStatus(result.data.statusId); - for (var i = 0; i < result.data.salesOrderLines.length; i++) { + for (let i = 0; i < result.data.salesOrderLines.length; i++) { this.addLineItem( result.data.salesOrderLines[i].id, result.data.salesOrderLines[i].itemId, result.data.salesOrderLines[i].measurementId, result.data.salesOrderLines[i].quantity, result.data.salesOrderLines[i].amount, - result.data.salesOrderLines[i].discount + result.data.salesOrderLines[i].discount, + result.data.salesOrderLines[i].code ); - this.updateLineItem(i, 'code', this.changeItemCode(result.data.salesOrderLines[i].itemId)); + this.updateLineItem(i, 'code', this.changeItemCode(result.data.salesOrderLines[i].itemId)!); } this.computeTotals(); - var nodes = document.getElementById("divSalesOrderForm").getElementsByTagName('*'); - for (var i = 0; i < nodes.length; i++) { + const nodes = document.getElementById("divSalesOrderForm")!.getElementsByTagName('*'); + for (let i = 0; i < nodes.length; i++) { nodes[i].className += " disabledControl"; } - }.bind(this)); + }); } else { @@ -96,52 +113,48 @@ export default class SalesOrderStore { } } - @observable RTotal = 0; - @observable GTotal = 0; - @observable TTotal = 0; - computeTotals() { - var rtotal = 0; - var ttotal = 0; - var gtotal = 0; + let rtotal = 0; + let ttotal = 0; - for (var i = 0; i < this.salesOrder.salesOrderLines.length; i++) { - var lineItem = this.salesOrder.salesOrderLines[i]; + for (let i = 0; i < this.salesOrder.salesOrderLines.length; i++) { + const lineItem = this.salesOrder.salesOrderLines[i]; rtotal = rtotal + this.getLineTotal(i); - axios.get(Config.apiUrl + "tax/gettax?itemId=" + lineItem.itemId + "&partyId=" + this.salesOrder.customerId + "&type=1") - .then(function (result) { + axios.get(Config.API_URL + "tax/gettax?itemId=" + lineItem.itemId + "&partyId=" + this.salesOrder.customerId + "&type=1") + .then((result) => { if (result.data.length > 0) { ttotal = ttotal + this.commonStore.getSalesLineTaxAmount(lineItem.quantity, lineItem.amount, lineItem.discount, result.data); } this.TTotal = ttotal; this.GTotal = rtotal + ttotal; - }.bind(this)); + }); this.RTotal = rtotal; } } saveNewSalesOrder() { - - if (this.salesOrder.orderDate === undefined) - this.salesOrder.orderDate = new Date(Date.now()).toISOString().substring(0, 10); + this.salesOrder.orderDate = new Date(new Date(Date.now()).toISOString().substring(0, 10)); if (this.validation() && this.validationErrors.length === 0) { - axios.post(Config.apiUrl + "sales/savesalesorder", JSON.stringify(this.salesOrder), + axios.post(Config.API_URL + "sales/savesalesorder", JSON.stringify(this.salesOrder), { headers: { 'Content-type': 'application/json' } }) - .then(function (response) { + .then(() => { window.location.href = baseUrl + 'sales/salesorders'; }) - .catch(function (error) { - error.data.map(function (err) { - this.validationErrors.push(err); - }.bind(this)); - }.bind(this)) + .catch((error) => { + if (axios.isAxiosError(error)) { + this.validationErrors.push(`Status: ${error.status} - Message: ${error.response?.data}`); + } else { + console.error(error); + this.validationErrors.push(`Error: ${error}`); + } + }) } } @@ -156,7 +169,7 @@ export default class SalesOrderStore { if (this.salesOrder.salesOrderLines === undefined || this.salesOrder.salesOrderLines.length < 1) this.validationErrors.push("Enter at least 1 line item."); if (this.salesOrder.salesOrderLines !== undefined && this.salesOrder.salesOrderLines.length > 0) { - for (var i = 0; i < this.salesOrder.salesOrderLines.length; i++) { + for (let i = 0; i < this.salesOrder.salesOrderLines.length; i++) { if (this.salesOrder.salesOrderLines[i].itemId === undefined) this.validationErrors.push("Item is required."); if (this.salesOrder.salesOrderLines[i].measurementId === undefined) @@ -180,7 +193,7 @@ export default class SalesOrderStore { validationLine() { this.validationErrors = []; if (this.salesOrder.salesOrderLines !== undefined && this.salesOrder.salesOrderLines.length > 0) { - for (var i = 0; i < this.salesOrder.salesOrderLines.length; i++) { + for (let i = 0; i < this.salesOrder.salesOrderLines.length; i++) { if (this.salesOrder.salesOrderLines[i].itemId === undefined) this.validationErrors.push("Item is required."); if (this.salesOrder.salesOrderLines[i].measurementId === undefined) @@ -195,12 +208,10 @@ export default class SalesOrderStore { } } else { - var itemId, measurementId, quantity, amount, discount; - itemId = (document.getElementById("optNewItemId") as HTMLInputElement).value; - measurementId = (document.getElementById("optNewMeasurementId") as HTMLInputElement).value; - quantity = (document.getElementById("txtNewQuantity") as HTMLInputElement).value; - amount = (document.getElementById("txtNewAmount") as HTMLInputElement).value; - discount = (document.getElementById("txtNewDiscount") as HTMLInputElement).value; + const itemId: string = (document.getElementById("optNewItemId") as HTMLInputElement).value; + const measurementId: string = (document.getElementById("optNewMeasurementId") as HTMLInputElement).value; + const quantity: string = (document.getElementById("txtNewQuantity") as HTMLInputElement).value; + const amount: string = (document.getElementById("txtNewAmount") as HTMLInputElement).value; if (itemId == "" || itemId === undefined) this.validationErrors.push("Item is required."); @@ -213,12 +224,10 @@ export default class SalesOrderStore { } if (document.getElementById("optNewItemId")) { - var itemId, measurementId, quantity, amount, discount; - itemId = (document.getElementById("optNewItemId") as HTMLInputElement).value; - measurementId = (document.getElementById("optNewMeasurementId") as HTMLInputElement).value; - quantity = (document.getElementById("txtNewQuantity") as HTMLInputElement).value; - amount = (document.getElementById("txtNewAmount") as HTMLInputElement).value; - discount = (document.getElementById("txtNewDiscount") as HTMLInputElement).value; + const itemId: string = (document.getElementById("optNewItemId") as HTMLInputElement).value; + const measurementId: string = (document.getElementById("optNewMeasurementId") as HTMLInputElement).value; + const quantity: string = (document.getElementById("txtNewQuantity") as HTMLInputElement).value; + const amount: string = (document.getElementById("txtNewAmount") as HTMLInputElement).value; if (itemId == "" || itemId === undefined) this.validationErrors.push("Item is required."); @@ -234,8 +243,8 @@ export default class SalesOrderStore { return this.validationErrors.length === 0; } - getQuotationStatus(statusId) { - var status = ""; + getQuotationStatus(statusId: number) { + let status = ""; if (statusId === 0) status = "Draft"; else if (statusId === 1) @@ -250,8 +259,8 @@ export default class SalesOrderStore { } - getOrderStatus(statusId) { - var status = ""; + getOrderStatus(statusId: number) { + let status = ""; if (statusId === 0) status = "Draft"; else if (statusId === 1) @@ -269,54 +278,55 @@ export default class SalesOrderStore { this.salesOrderStatus = status; } - changeItemCode(itemId) { - - for (var x = 0; x < this.commonStore.items.length; x++) { - if (this.commonStore.items[x].id === parseInt(itemId)) { - return this.commonStore.items[x].code; + changeItemCode(itemId: number) { + for (let x = 0; x < this.commonStore.items.length; x++) { + const lineItem = this.commonStore.items[x] as SalesOrderLine; + if (lineItem.id === itemId) { + return lineItem.code; } } } - changedReferenceNo(refNo) { + changedReferenceNo(refNo: string) { this.salesOrder.referenceNo = refNo; } - changedCustomer(custId) { + + changedCustomer(custId: number) { this.salesOrder.customerId = custId; } - changedOrderDate(date) { + changedOrderDate(date: Date) { this.salesOrder.orderDate = date; } - changedPaymentTerm(termId) { + changedPaymentTerm(termId: number) { this.salesOrder.paymentTermId = termId; } - addLineItem(id, itemId, measurementId, quantity, amount, discount, code) { - var newLineItem = new SalesOrderLine(id, itemId, measurementId, quantity, amount, discount, code); + addLineItem(id: number, itemId: number, measurementId: number, quantity: number, amount: number, discount: number, code: string) { + const newLineItem = new SalesOrderLine(id, itemId, measurementId, quantity, amount, discount, code); this.salesOrder.salesOrderLines.push(extendObservable(newLineItem, newLineItem)); } - removeLineItem(row) { + removeLineItem(row: number) { this.salesOrder.salesOrderLines.splice(row, 1); } - updateLineItem(row, targetProperty, value) { + updateLineItem(row: number, targetProperty: keyof SalesOrderLine, value: string | number) { if (this.salesOrder.salesOrderLines.length > 0) - this.salesOrder.salesOrderLines[row][targetProperty] = value; + (this.salesOrder.salesOrderLines[row] as Record)[targetProperty] = value; this.computeTotals(); } - getLineTotal(row) { + getLineTotal(row: number) { let lineSum = 0; - let lineItem = this.salesOrder.salesOrderLines[row]; + const lineItem = this.salesOrder.salesOrderLines[row]; lineSum = (lineItem.quantity * lineItem.amount) - lineItem.discount; return lineSum; } - changedEditMode(editMode) { + changedEditMode(editMode: boolean) { this.editMode = editMode; } } \ No newline at end of file diff --git a/src/GoodBooksReact/src/components/Shared/Stores/TaxSystem/Tax.tsx b/src/GoodBooksReact/src/components/Shared/Stores/TaxSystem/Tax.tsx new file mode 100644 index 000000000..7a7d2a025 --- /dev/null +++ b/src/GoodBooksReact/src/components/Shared/Stores/TaxSystem/Tax.tsx @@ -0,0 +1,6 @@ +export default class SalesOrder { + id: number = 0; + code: string = ''; + name: string = ''; + rate: number = 0; +} \ No newline at end of file diff --git a/src/AccountGoWeb/Scripts/Shared/Stores/TaxSystem/TaxConfigStore.tsx b/src/GoodBooksReact/src/components/Shared/Stores/TaxSystem/TaxConfigStore.tsx similarity index 100% rename from src/AccountGoWeb/Scripts/Shared/Stores/TaxSystem/TaxConfigStore.tsx rename to src/GoodBooksReact/src/components/Shared/Stores/TaxSystem/TaxConfigStore.tsx diff --git a/src/AccountGoWeb/Scripts/Test/Hello.tsx b/src/GoodBooksReact/src/components/Test/Hello.tsx similarity index 85% rename from src/AccountGoWeb/Scripts/Test/Hello.tsx rename to src/GoodBooksReact/src/components/Test/Hello.tsx index c0c769314..f6af1142c 100644 --- a/src/AccountGoWeb/Scripts/Test/Hello.tsx +++ b/src/GoodBooksReact/src/components/Test/Hello.tsx @@ -5,7 +5,7 @@ interface HelloProps { name: string; } -class Hello extends React.Component { +class Hello extends React.Component> { render() { return
    Hello, {this.props.name}. If you can see this message means you have successfully configured reactjs+typescript+webpack+babel-loader.
    ; } diff --git a/src/GoodBooksReact/src/components/src/@types/index.d.ts.delete b/src/GoodBooksReact/src/components/src/@types/index.d.ts.delete new file mode 100644 index 000000000..4c57082fe --- /dev/null +++ b/src/GoodBooksReact/src/components/src/@types/index.d.ts.delete @@ -0,0 +1,11 @@ +// Fixes TS2694 +declare global { + namespace React { + /** Fixes React 18 compatibility issues with formik: https://github.com/jaredpalmer/formik/issues/3546#issuecomment-1127014775 */ + type StatelessComponent

    = React.FunctionComponent

    ; + } + } + + // Fixes TS2669 + export {}; + \ No newline at end of file diff --git a/src/GoodBooksReact/src/index.css b/src/GoodBooksReact/src/index.css new file mode 100644 index 000000000..8e93d311a --- /dev/null +++ b/src/GoodBooksReact/src/index.css @@ -0,0 +1,68 @@ +:root { + font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; + line-height: 1.5; + font-weight: 400; + + color-scheme: light dark; + color: rgba(255, 255, 255, 0.87); + background-color: #242424; + + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +a { + font-weight: 500; + color: #646cff; + text-decoration: inherit; +} +a:hover { + color: #535bf2; +} + +body { + margin: 0; + /* display: flex; */ + place-items: center; + min-width: 320px; + min-height: 100vh; +} + +h1 { + font-size: 3.2em; + line-height: 1.1; +} + +button { + border-radius: 8px; + border: 1px solid transparent; + padding: 0.6em 1.2em; + font-size: 1em; + font-weight: 500; + font-family: inherit; + background-color: #1a1a1a; + cursor: pointer; + transition: border-color 0.25s; +} +button:hover { + border-color: #646cff; +} +button:focus, +button:focus-visible { + outline: 4px auto -webkit-focus-ring-color; +} + +@media (prefers-color-scheme: light) { + :root { + color: #213547; + background-color: #ffffff; + } + a:hover { + color: #747bff; + } + button { + background-color: #f9f9f9; + } +} diff --git a/src/GoodBooksReact/src/main.tsx b/src/GoodBooksReact/src/main.tsx new file mode 100644 index 000000000..1ccafcbf1 --- /dev/null +++ b/src/GoodBooksReact/src/main.tsx @@ -0,0 +1,14 @@ +import React from 'react' +import ReactDOM from 'react-dom/client' +// import App from './App.tsx' +import './index.css' +import { RouterProvider } from 'react-router' +import {router} from './routes/Routes' +import "bootstrap/dist/css/bootstrap.min.css"; +import "bootstrap/dist/js/bootstrap.min.js"; + +ReactDOM.createRoot(document.getElementById('root')!).render( + + + , +) diff --git a/src/GoodBooksReact/src/routes/Routes.tsx b/src/GoodBooksReact/src/routes/Routes.tsx new file mode 100644 index 000000000..dc4ddd1b1 --- /dev/null +++ b/src/GoodBooksReact/src/routes/Routes.tsx @@ -0,0 +1,41 @@ +import { createBrowserRouter } from "react-router-dom"; +import App from "../App"; +import JournalEntry from "../components/Financials/JournalEntry" +import ObservedPurchaseInvoice from "../components/Purchasing/PurchaseInvoice"; +import ObservedAddPurchaseOrder from "../components/Purchasing/PurchaseOrder"; +import ObservedSalesInvoice from "../components/Sales/SalesInvoice"; +import ObservedSalesOrder from "../components/Sales/SalesOrder"; + + +export const router = createBrowserRouter([ + { + path: "/", + element: , + children: [ + { + path: "/journal-entry", + element: + }, + { + path: "/purchasing-invoice", + element: + }, + { + path: "/purchase-order", + element: + }, + { + path: "/sales-invoice", + element: + }, + { + path: "/sales-order", + element: + }, + { + path: "/company/:id", + element:

    About

    + } + ] + } +]); \ No newline at end of file diff --git a/src/GoodBooksReact/src/vite-env.d.ts b/src/GoodBooksReact/src/vite-env.d.ts new file mode 100644 index 000000000..11f02fe2a --- /dev/null +++ b/src/GoodBooksReact/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/src/GoodBooksReact/tsconfig.json b/src/GoodBooksReact/tsconfig.json new file mode 100644 index 000000000..bdd1de0fe --- /dev/null +++ b/src/GoodBooksReact/tsconfig.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src"], + "references": [{ "path": "./tsconfig.node.json" }], + "exclude": [ + "node_modules" + ] +} diff --git a/src/GoodBooksReact/tsconfig.node.json b/src/GoodBooksReact/tsconfig.node.json new file mode 100644 index 000000000..42872c59f --- /dev/null +++ b/src/GoodBooksReact/tsconfig.node.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler", + "allowSyntheticDefaultImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/src/GoodBooksReact/vite.config.ts b/src/GoodBooksReact/vite.config.ts new file mode 100644 index 000000000..5a33944a9 --- /dev/null +++ b/src/GoodBooksReact/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [react()], +}) diff --git a/src/AccountGoWeb/webpack.config.js b/src/GoodBooksReact/webpack.config.js similarity index 98% rename from src/AccountGoWeb/webpack.config.js rename to src/GoodBooksReact/webpack.config.js index 3578655ef..3b51f29a6 100644 --- a/src/AccountGoWeb/webpack.config.js +++ b/src/GoodBooksReact/webpack.config.js @@ -70,4 +70,4 @@ var config = { } }; -module.exports = config; \ No newline at end of file +module.exports = config; diff --git a/src/Infrastructure/Infrastructure.csproj b/src/Infrastructure/Infrastructure.csproj index 641831e7a..e6de2fed8 100644 --- a/src/Infrastructure/Infrastructure.csproj +++ b/src/Infrastructure/Infrastructure.csproj @@ -3,12 +3,13 @@ netstandard2.1 Library + true - + - + diff --git a/src/LibraryGDB/LibraryGDB.csproj b/src/LibraryGDB/LibraryGDB.csproj new file mode 100644 index 000000000..b7cb6bbad --- /dev/null +++ b/src/LibraryGDB/LibraryGDB.csproj @@ -0,0 +1,14 @@ + + + net9.0 + enable + enable + + + + + + + + + \ No newline at end of file diff --git a/src/LibraryGDB/Models/Account/LoginViewModel.cs b/src/LibraryGDB/Models/Account/LoginViewModel.cs new file mode 100644 index 000000000..55e4ddd8e --- /dev/null +++ b/src/LibraryGDB/Models/Account/LoginViewModel.cs @@ -0,0 +1,17 @@ +using System.ComponentModel.DataAnnotations; + +namespace LibraryGDB.Models.Account; + +public class LoginViewModel +{ + [Required] + [EmailAddress] + public string? Email { get; set; } + + [Required] + [DataType(DataType.Password)] + public string? Password { get; set; } + + [Display(Name = "Remember me?")] + public bool RememberMe { get; set; } +} diff --git a/src/LibraryGDB/Models/Account/RegisterViewModel.cs b/src/LibraryGDB/Models/Account/RegisterViewModel.cs new file mode 100644 index 000000000..f035c0f38 --- /dev/null +++ b/src/LibraryGDB/Models/Account/RegisterViewModel.cs @@ -0,0 +1,28 @@ +using System.ComponentModel.DataAnnotations; + +namespace LibraryGDB.Models.Account; + +public class RegisterViewModel +{ + [Required] + [EmailAddress] + [Display(Name = "Email")] + public string? Email { get; set; } + + [Required] + [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)] + [DataType(DataType.Password)] + [Display(Name = "Password")] + public string? Password { get; set; } + + [DataType(DataType.Password)] + [Display(Name = "Confirm password")] + [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")] + public string? ConfirmPassword { get; set; } + + [Display(Name = "First Name")] + public string? FirstName { get; set; } + + [Display(Name = "Last Name")] + public string? LastName { get; set; } +} diff --git a/src/LibraryGDB/Models/Bogus/Student.cs b/src/LibraryGDB/Models/Bogus/Student.cs new file mode 100644 index 000000000..1797888ba --- /dev/null +++ b/src/LibraryGDB/Models/Bogus/Student.cs @@ -0,0 +1,62 @@ +namespace LibraryGDB.Models.Bogus; + +public class Student +{ + required public int? Id { get; set; } + required public string FirstName { get; set; } + required public string LastName { get; set; } + required public string School { get; set; } + public static IQueryable GetStudents() + { + int ndx = 0; + List students = new List() { + new Student() { Id = ++ndx, FirstName="Max", LastName="Pao", School="Science" }, + new Student() { Id = ++ndx, FirstName="Tom", LastName="Fay", School="Mining" }, + new Student() { Id = ++ndx, FirstName="Ann", LastName="Sun", School="Nursing" }, + new Student() { Id = ++ndx, FirstName="Joe", LastName="Fox", School="Computing" }, + new Student() { Id = ++ndx, FirstName="Sue", LastName="Mai", School="Mining" }, + new Student() { Id = ++ndx, FirstName="Ben", LastName="Lau", School="Business" }, + new Student() { Id = ++ndx, FirstName="Zoe", LastName="Ray", School="Mining" }, + new Student() { Id = ++ndx, FirstName="Sam", LastName="Ash", School="Medicine" }, + new Student() { Id = ++ndx, FirstName="Dan", LastName="Lee", School="Computing" }, + new Student() { Id = ++ndx, FirstName="Pat", LastName="Day", School="Science" }, + new Student() { Id = ++ndx, FirstName="Kim", LastName="Rex", School="Computing" }, + new Student() { Id = ++ndx, FirstName="Tim", LastName="Ram", School="Business" }, + new Student() { Id = ++ndx, FirstName="Rob", LastName="Wei", School="Mining" }, + new Student() { Id = ++ndx, FirstName="Jan", LastName="Tex", School="Science" }, + new Student() { Id = ++ndx, FirstName="Jim", LastName="Kid", School="Business" }, + new Student() { Id = ++ndx, FirstName="Ben", LastName="Chu", School="Medicine" }, + new Student() { Id = ++ndx, FirstName="Mia", LastName="Tao", School="Computing" }, + new Student() { Id = ++ndx, FirstName="Ted", LastName="Day", School="Business" }, + new Student() { Id = ++ndx, FirstName="Amy", LastName="Roy", School="Science" }, + new Student() { Id = ++ndx, FirstName="Ian", LastName="Kit", School="Nursing" }, + new Student() { Id = ++ndx, FirstName="Liz", LastName="Tan", School="Medicine" }, + new Student() { Id = ++ndx, FirstName="Mat", LastName="Roy", School="Tourism" }, + new Student() { Id = ++ndx, FirstName="Deb", LastName="Luo", School="Medicine" }, + new Student() { Id = ++ndx, FirstName="Ana", LastName="Poe", School="Computing" }, + new Student() { Id = ++ndx, FirstName="Lyn", LastName="Raj", School="Science" }, + new Student() { Id = ++ndx, FirstName="Amy", LastName="Ash", School="Tourism" }, + new Student() { Id = ++ndx, FirstName="Kim", LastName="Kid", School="Mining" }, + new Student() { Id = ++ndx, FirstName="Bec", LastName="Fry", School="Nursing" }, + new Student() { Id = ++ndx, FirstName="Eva", LastName="Lap", School="Computing" }, + new Student() { Id = ++ndx, FirstName="Eli", LastName="Yim", School="Business" }, + new Student() { Id = ++ndx, FirstName="Sam", LastName="Hui", School="Science" }, + new Student() { Id = ++ndx, FirstName="Joe", LastName="Jin", School="Mining" }, + new Student() { Id = ++ndx, FirstName="Liz", LastName="Kuo", School="Agriculture" }, + new Student() { Id = ++ndx, FirstName="Ric", LastName="Mak", School="Tourism" }, + new Student() { Id = ++ndx, FirstName="Pam", LastName="Day", School="Computing" }, + new Student() { Id = ++ndx, FirstName="Stu", LastName="Gad", School="Business" }, + new Student() { Id = ++ndx, FirstName="Tom", LastName="Bee", School="Tourism" }, + new Student() { Id = ++ndx, FirstName="Bob", LastName="Lam", School="Agriculture" }, + new Student() { Id = ++ndx, FirstName="Jim", LastName="Ots", School="Medicine" }, + new Student() { Id = ++ndx, FirstName="Tom", LastName="Mag", School="Mining" }, + new Student() { Id = ++ndx, FirstName="Hal", LastName="Doe", School="Agriculture" }, + new Student() { Id = ++ndx, FirstName="Roy", LastName="Kim", School="Nursing" }, + new Student() { Id = ++ndx, FirstName="Vis", LastName="Cox", School="Science" }, + new Student() { Id = ++ndx, FirstName="Kay", LastName="Aga", School="Tourism" }, + new Student() { Id = ++ndx, FirstName="Reo", LastName="Hui", School="Business" }, + new Student() { Id = ++ndx, FirstName="Bob", LastName="Roe", School="Medicine" }, + }; + return students.AsQueryable(); + } +} diff --git a/src/LibraryGDB/Models/Constants.cs b/src/LibraryGDB/Models/Constants.cs new file mode 100644 index 000000000..c47aa4b7d --- /dev/null +++ b/src/LibraryGDB/Models/Constants.cs @@ -0,0 +1,6 @@ +namespace LibraryGDB.Models; + +public class Constants +{ + public const string API_URL = "http://goodbooksapi.azurewebsites.net/api/"; +} diff --git a/src/LibraryGDB/Models/Financial/AccountViewModel.cs b/src/LibraryGDB/Models/Financial/AccountViewModel.cs new file mode 100644 index 000000000..fd8974fb7 --- /dev/null +++ b/src/LibraryGDB/Models/Financial/AccountViewModel.cs @@ -0,0 +1,13 @@ +namespace LibraryGDB.Models.Financial +{ + public class AccountViewModel + { + public string? AccountCode { get; set; } + public string? AccountName { get; set; } + public decimal TotalBalance { get; set; } + public decimal TotalDebitBalance { get; set; } + public decimal TotalCreditBalance { get; set; } + public IList? ChildAccounts { get; set; } + + } +} diff --git a/src/LibraryGDB/Models/Financial/GeneralLedgerSetting.cs b/src/LibraryGDB/Models/Financial/GeneralLedgerSetting.cs new file mode 100644 index 000000000..f41dd90b1 --- /dev/null +++ b/src/LibraryGDB/Models/Financial/GeneralLedgerSetting.cs @@ -0,0 +1,13 @@ +namespace LibraryGDB.Models.Financial; + +public class GeneralLedgerSetting +{ + public int Id { get; set; } + public int? CompanyId { get; set; } + public string? CompanyCode { get; set; } + public int? PayableAccountId { get; set; } + public int? PurchaseDiscountAccountId { get; set; } + public int? GoodsReceiptNoteClearingAccountId { get; set; } + public int? SalesDiscountAccountId { get; set; } + public int? ShippingChargeAccountId { get; set; } +} diff --git a/src/LibraryGDB/Models/FinancialReports.cs b/src/LibraryGDB/Models/FinancialReports.cs new file mode 100644 index 000000000..24eeb4e7b --- /dev/null +++ b/src/LibraryGDB/Models/FinancialReports.cs @@ -0,0 +1,42 @@ +namespace LibraryGDB.Models; + +public class TrialBalance +{ + public int AccountId { get; set; } + public string? AccountCode { get; set; } + public string? AccountName { get; set; } + public decimal Debit { get; set; } + public decimal Credit { get; set; } +} + +public class BalanceSheet +{ + public int AccountId { get; set; } + public int AccountClassId { get; set; } + public string? AccountCode { get; set; } + public string? AccountName { get; set; } + public decimal Amount { get; set; } +} + +public class IncomeStatement +{ + public int AccountId { get; set; } + public bool IsExpense { get; set; } + public string? AccountCode { get; set; } + public string? AccountName { get; set; } + public decimal Amount { get; set; } +} + +public partial class MasterGeneralLedger +{ + public int Id { get; set; } + public int AccountId { get; set; } + public int CurrencyId { get; set; } + public string? DocumentType { get; set; } + public int TransactionNo { get; set; } + public string? AccountCode { get; set; } + public string? AccountName { get; set; } + public DateTime Date { get; set; } + public decimal Debit { get; set; } + public decimal Credit { get; set; } +} diff --git a/src/LibraryGDB/Models/ObjectExtensions.cs b/src/LibraryGDB/Models/ObjectExtensions.cs new file mode 100644 index 000000000..82057bca2 --- /dev/null +++ b/src/LibraryGDB/Models/ObjectExtensions.cs @@ -0,0 +1,14 @@ +using Newtonsoft.Json; + +namespace LibraryGDB.Models; + +public static class ObjectExtensions +{ + public static string ToJson(this object obj) + { + JsonSerializer js = JsonSerializer.Create(new JsonSerializerSettings()); + var jw = new StringWriter(); + js.Serialize(jw, obj); + return jw.ToString(); + } +} diff --git a/src/LibraryGDB/Models/Purchasing/Payment.cs b/src/LibraryGDB/Models/Purchasing/Payment.cs new file mode 100644 index 000000000..32f53bb9a --- /dev/null +++ b/src/LibraryGDB/Models/Purchasing/Payment.cs @@ -0,0 +1,18 @@ +namespace LibraryGDB.Models.Purchasing; + +public class Payment +{ + public int InvoiceId { get; set; } + public string? InvoiceNo { get; set; } + public int VendorId { get; set; } + public string? VendorName { get; set; } + public decimal InvoiceAmount { get; set; } + public decimal AmountPaid { get; set; } + public decimal Balance { get { return InvoiceAmount - AmountPaid; } } + [ExpressiveAnnotations.Attributes.AssertThat("AmountToPay <= Balance", ErrorMessage = "Amount to pay cannot be greater than remaining amount to pay.")] + [ExpressiveAnnotations.Attributes.AssertThat("AmountToPay > 0", ErrorMessage = "Amount to pay cannot be zero.")] + public decimal AmountToPay { get; set; } + [System.ComponentModel.DataAnnotations.Required] + public int? AccountId { get; set; } + public System.DateTime Date { get; set; } +} diff --git a/src/LibraryGDB/Models/Sales/AddSalesReceipt.cs b/src/LibraryGDB/Models/Sales/AddSalesReceipt.cs new file mode 100644 index 000000000..70c86ad9b --- /dev/null +++ b/src/LibraryGDB/Models/Sales/AddSalesReceipt.cs @@ -0,0 +1,19 @@ +namespace LibraryGDB.Models.Sales; + +public class AddReceipt +{ + [System.ComponentModel.DataAnnotations.Required] + public int? AccountToDebitId { get; set; } + [System.ComponentModel.DataAnnotations.Required] + public int? AccountToCreditId { get; set; } + [System.ComponentModel.DataAnnotations.Required] + public int? CustomerId { get; set; } + public System.DateTime ReceiptDate {get;set;} + [ExpressiveAnnotations.Attributes.AssertThat("Amount > 0", ErrorMessage = "Amount cannot be zero.")] + public decimal Amount { get; set; } + + public AddReceipt() + { + ReceiptDate = System.DateTime.Now; + } +} diff --git a/src/LibraryGDB/Models/Sales/Allocate.cs b/src/LibraryGDB/Models/Sales/Allocate.cs new file mode 100644 index 000000000..c8aab57a0 --- /dev/null +++ b/src/LibraryGDB/Models/Sales/Allocate.cs @@ -0,0 +1,48 @@ +namespace LibraryGDB.Models.Sales; + +public class Allocate +{ + [System.ComponentModel.DataAnnotations.Required] + public int? CustomerId { get; set; } + [System.ComponentModel.DataAnnotations.Required] + public int? ReceiptId { get; set; } + [System.ComponentModel.DataAnnotations.Required] + public System.DateTime Date { get; set; } + public decimal Amount { get; set; } + public decimal RemainingAmountToAllocate { get; set; } + public decimal SumAllocatedAmount { get { return ComputeSumToAllocateAmount(); } } + public IList AllocationLines { get; set; } + + public Allocate() + { + AllocationLines = new List(); + } + + private decimal ComputeSumToAllocateAmount() + { + decimal sum = 0; + + foreach (var line in AllocationLines) { + sum += line.AmountToAllocate.GetValueOrDefault(); + } + + return sum; + } + + public bool IsValid() + { + if (RemainingAmountToAllocate < SumAllocatedAmount) + return false; + else + return true; + } +} + +public class AllocationLine +{ + [System.ComponentModel.DataAnnotations.Required] + public int? InvoiceId { get; set; } + public decimal? Amount { get; set; } + public decimal? AllocatedAmount { get; set; } + public decimal? AmountToAllocate { get; set; } +} diff --git a/src/LibraryGDB/Models/Sales/SalesQuotation.cs b/src/LibraryGDB/Models/Sales/SalesQuotation.cs new file mode 100644 index 000000000..a57ed20b1 --- /dev/null +++ b/src/LibraryGDB/Models/Sales/SalesQuotation.cs @@ -0,0 +1,21 @@ +namespace LibraryGDB.Models.Sales; +public class SalesQuotations { + [System.ComponentModel.DataAnnotations.Required] + public int CustomerId { get; set; } + [System.ComponentModel.DataAnnotations.Required] + public int PaymentTermId { get; set; } + [System.ComponentModel.DataAnnotations.Required] + public int ItemId { get; set; } + [System.ComponentModel.DataAnnotations.Required] + public int Quantity { get; set; } + [ExpressiveAnnotations.Attributes.AssertThat("Amount > 0", ErrorMessage = "Amount cannot be zero.")] + public decimal Amount { get; set; } + public System.DateTime Date { get; set; } + public decimal Discount { get; set; } + + public SalesQuotations() + { + Date = System.DateTime.Now; + } + +} \ No newline at end of file diff --git a/src/LibraryGDB/Models/SelectListItemHelper.cs b/src/LibraryGDB/Models/SelectListItemHelper.cs new file mode 100644 index 000000000..3350dc017 --- /dev/null +++ b/src/LibraryGDB/Models/SelectListItemHelper.cs @@ -0,0 +1,149 @@ +using Microsoft.Extensions.Configuration; + +namespace LibraryGDB.Models; + +public static class SelectListItemHelper +{ + public static IConfiguration? _config; + + public static IEnumerable Accounts() + { + var accounts = GetAsync>("common/postingaccounts").Result; + + var selectAccounts = new HashSet(); + selectAccounts.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = "", Text = "" }); + foreach (var account in accounts) + selectAccounts.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = account.Id.ToString(), Text = account.AccountName }); + + return selectAccounts; + } + + public static IEnumerable TaxGroups() + { + var taxGroups = GetAsync>("tax/taxgroups").Result; + var selectTaxGroups = new HashSet(); + selectTaxGroups.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = "", Text = "" }); + foreach (var taxGroup in taxGroups) + selectTaxGroups.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = taxGroup.Id.ToString(), Text = taxGroup.Description }); + + return selectTaxGroups; + } + + public static IEnumerable ItemTaxGroups() + { + var itemtaxgroups = GetAsync>("tax/itemtaxgroups").Result; + var selectitemtaxgroups = new HashSet(); + selectitemtaxgroups.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = "", Text = "" }); + foreach (var taxGroup in itemtaxgroups) + selectitemtaxgroups.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = taxGroup.Id.ToString(), Text = taxGroup.Name }); + + return selectitemtaxgroups; + } + + public static IEnumerable PaymentTerms() + { + var paymentTerms = GetAsync>("common/paymentterms").Result; + var selectPaymentTerms = new HashSet(); + selectPaymentTerms.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = "", Text = "" }); + foreach (var term in paymentTerms) + selectPaymentTerms.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = term.Id.ToString(), Text = term.Description }); + + return selectPaymentTerms; + } + + public static IEnumerable UnitOfMeasurements() + { + var uoms = GetAsync>("common/measurements").Result; + var selectUOMS = new HashSet(); + selectUOMS.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = "", Text = "" }); + foreach (var item in uoms) + selectUOMS.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = item.Id.ToString(), Text = item.Description }); + + return selectUOMS; + } + + public static IEnumerable ItemCategories() + { + var categories = GetAsync>("common/itemcategories").Result; + var selectCategories = new HashSet(); + selectCategories.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = "", Text = "" }); + foreach (var item in categories) + selectCategories.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = item.Id.ToString(), Text = item.Name }); + + return selectCategories; + } + + public static IEnumerable CashBanks() + { + var cashBanks = GetAsync>("common/cashbanks").Result; + var selectCashBanks = new HashSet(); + selectCashBanks.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = "", Text = "" }); + foreach (var item in cashBanks) + selectCashBanks.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = item.Id.ToString(), Text = item.Name }); + + return selectCashBanks; + } + + public static IEnumerable Customers() + { + var customers = GetAsync>("sales/customers").Result; + var selectCustomers = new HashSet(); + selectCustomers.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = "", Text = "" }); + foreach (var item in customers) + selectCustomers.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = item.Id.ToString(), Text = item.Name }); + + return selectCustomers; + } + + public static IEnumerable Vendors() + { + var vendors = GetAsync>("purchasing/vendors").Result; + var selectVendors = new HashSet(); + selectVendors.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = "", Text = "" }); + foreach (var item in vendors) + selectVendors.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = item.Id.ToString(), Text = item.Name }); + + return selectVendors; + } + + public static IEnumerable Items() + { + var items = GetAsync>("inventory/items").Result; + var selectItems = new HashSet(); + selectItems.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = "", Text = "" }); + foreach (var item in items) + selectItems.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = item.Id.ToString(), Text = item.Description }); + + return selectItems; + } + + public static IEnumerable Measurements() + { + var measurements = GetAsync>("common/measurements").Result; + var selectMeasurements = new HashSet(); + selectMeasurements.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = "", Text = "" }); + foreach (var item in measurements) + selectMeasurements.Add(new Microsoft.AspNetCore.Mvc.Rendering.SelectListItem() { Value = item.Id.ToString(), Text = item.Description }); + + return selectMeasurements; + } + + #region Private methods + public static async System.Threading.Tasks.Task GetAsync(string uri) + { + string responseJson = string.Empty; + using (var client = new HttpClient()) + { + var baseUri = _config!["ApiUrl"]; + client.BaseAddress = new System.Uri(baseUri!); + client.DefaultRequestHeaders.Accept.Clear(); + var response = await client.GetAsync(baseUri + uri); + if (response.IsSuccessStatusCode) + { + responseJson = await response.Content.ReadAsStringAsync(); + } + } + return Newtonsoft.Json.JsonConvert.DeserializeObject(responseJson)!; + } + #endregion +} diff --git a/src/LibraryGDB/Models/TaxSystem/TaxSystemViewModel.cs b/src/LibraryGDB/Models/TaxSystem/TaxSystemViewModel.cs new file mode 100644 index 000000000..c4e35d315 --- /dev/null +++ b/src/LibraryGDB/Models/TaxSystem/TaxSystemViewModel.cs @@ -0,0 +1,9 @@ +using Dto.TaxSystem; + +namespace LibraryGDB.Models.TaxSystem; +public class TaxSystemViewModel +{ + public System.Collections.Generic.IEnumerable? Taxes { get; set; } + public System.Collections.Generic.IEnumerable? TaxGroups { get; set; } + public System.Collections.Generic.IEnumerable? ItemTaxGroups { get; set; } +} diff --git a/src/MigrationService/MigrationService.csproj b/src/MigrationService/MigrationService.csproj new file mode 100644 index 000000000..220e8fab8 --- /dev/null +++ b/src/MigrationService/MigrationService.csproj @@ -0,0 +1,19 @@ + + + + net9.0 + enable + enable + dotnet-MigrationService-dcc1af79-957f-42b3-8462-759768f83a25 + + + + + + + + + + + + diff --git a/src/MigrationService/Program.cs b/src/MigrationService/Program.cs new file mode 100644 index 000000000..db7411b66 --- /dev/null +++ b/src/MigrationService/Program.cs @@ -0,0 +1,17 @@ +using Api.Data; +using MigrationService; + +var builder = Host.CreateApplicationBuilder(args); + +builder.AddServiceDefaults(); + +builder.Services.AddHostedService(); + +builder.Services.AddOpenTelemetry() + .WithTracing(tracing => tracing.AddSource(Worker.ActivitySourceName)); + +builder.AddSqlServerDbContext("gdb-db"); +builder.AddSqlServerDbContext("gdb-db"); + +var host = builder.Build(); +host.Run(); diff --git a/src/MigrationService/Properties/launchSettings.json b/src/MigrationService/Properties/launchSettings.json new file mode 100644 index 000000000..7f5b75dde --- /dev/null +++ b/src/MigrationService/Properties/launchSettings.json @@ -0,0 +1,12 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "profiles": { + "MigrationService": { + "commandName": "Project", + "dotnetRunMessages": true, + "environmentVariables": { + "DOTNET_ENVIRONMENT": "Development" + } + } + } +} diff --git a/src/MigrationService/Worker.cs b/src/MigrationService/Worker.cs new file mode 100644 index 000000000..b0bbf17ce --- /dev/null +++ b/src/MigrationService/Worker.cs @@ -0,0 +1,87 @@ +using System.Diagnostics; +using Api.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Storage; + +using OpenTelemetry.Trace; + +namespace MigrationService; + +public class Worker( + IServiceProvider serviceProvider, + IHostApplicationLifetime hostApplicationLifetime) : BackgroundService +{ + public const string ActivitySourceName = "Migrations"; + private static readonly ActivitySource s_activitySource = new(ActivitySourceName); + + protected override async Task ExecuteAsync(CancellationToken cancellationToken) + { + using var activity = s_activitySource.StartActivity("Migrating database", ActivityKind.Client); + + try + { + using var scope = serviceProvider.CreateScope(); + var dbContext = scope.ServiceProvider.GetRequiredService(); + + await EnsureDatabaseAsync(dbContext, cancellationToken); + await RunMigrationAsync(dbContext, cancellationToken); + // await SeedDataAsync(dbContext, cancellationToken); + } + catch (Exception ex) + { + activity?.RecordException(ex); + throw; + } + + hostApplicationLifetime.StopApplication(); + } + + private static async Task EnsureDatabaseAsync(ApiDbContext dbContext, CancellationToken cancellationToken) + { + var dbCreator = dbContext.GetService(); + + var strategy = dbContext.Database.CreateExecutionStrategy(); + await strategy.ExecuteAsync(async () => + { + // Create the database if it does not exist. + // Do this first so there is then a database to start a transaction against. + if (!await dbCreator.ExistsAsync(cancellationToken)) + { + await dbCreator.CreateAsync(cancellationToken); + } + }); + } + + private static async Task RunMigrationAsync(ApiDbContext dbContext, CancellationToken cancellationToken) + { + var strategy = dbContext.Database.CreateExecutionStrategy(); + await strategy.ExecuteAsync(async () => + { + // Run migration in a transaction to avoid partial migration if it fails. + await using var transaction = await dbContext.Database.BeginTransactionAsync(cancellationToken); + await dbContext.Database.MigrateAsync(cancellationToken); + await transaction.CommitAsync(cancellationToken); + }); + } + + // private static async Task SeedDataAsync(ApiDbContext dbContext, CancellationToken cancellationToken) + // { + // SupportTicket firstTicket = new() + // { + // Title = "Test Ticket", + // Description = "Default ticket, please ignore!", + // Completed = true + // }; + + // var strategy = dbContext.Database.CreateExecutionStrategy(); + // await strategy.ExecuteAsync(async () => + // { + // // Seed the database + // await using var transaction = await dbContext.Database.BeginTransactionAsync(cancellationToken); + // await dbContext.Tickets.AddAsync(firstTicket, cancellationToken); + // await dbContext.SaveChangesAsync(cancellationToken); + // await transaction.CommitAsync(cancellationToken); + // }); + // } +} \ No newline at end of file diff --git a/src/Api/appsettings.Development.json b/src/MigrationService/appsettings.Development.json similarity index 80% rename from src/Api/appsettings.Development.json rename to src/MigrationService/appsettings.Development.json index 45fe774a9..b2dcdb674 100644 --- a/src/Api/appsettings.Development.json +++ b/src/MigrationService/appsettings.Development.json @@ -2,8 +2,7 @@ "Logging": { "LogLevel": { "Default": "Information", - "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" } } -} \ No newline at end of file +} diff --git a/src/MigrationService/appsettings.json b/src/MigrationService/appsettings.json new file mode 100644 index 000000000..b2dcdb674 --- /dev/null +++ b/src/MigrationService/appsettings.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.Hosting.Lifetime": "Information" + } + } +} diff --git a/src/Modules/SampleModule/SampleModule.csproj b/src/Modules/SampleModule/SampleModule.csproj index 0cd412945..e48a10a1a 100644 --- a/src/Modules/SampleModule/SampleModule.csproj +++ b/src/Modules/SampleModule/SampleModule.csproj @@ -1,12 +1,11 @@ - netstandard2.1 + net8.0 - - - + + diff --git a/src/Services/Administration/AdministrationService.cs b/src/Services/Administration/AdministrationService.cs index 95b48565b..e8533d30a 100644 --- a/src/Services/Administration/AdministrationService.cs +++ b/src/Services/Administration/AdministrationService.cs @@ -6,14 +6,22 @@ // //----------------------------------------------------------------------- +using AutoMapper; using Core.Data; using Core.Domain; using Core.Domain.Auditing; +using Core.Domain.Error; using Core.Domain.Financials; using Core.Domain.Security; using Core.Domain.TaxSystem; +using Services.Financial; +using Services.TaxSystem; +using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.CompilerServices; +using System.Security.Cryptography; +using System.Threading.Tasks; namespace Services.Administration { @@ -30,6 +38,9 @@ public class AdministrationService : BaseService, IAdministrationService private readonly IRepository _accountRepo; private readonly IRepository _auditLogRepo; private readonly ISecurityRepository _securityRepository; + private readonly IFinancialService _financialService; + private readonly ITaxService _taxService; + private readonly IMapper _mapper; public AdministrationService(IRepository fiscalYearRepo, IRepository taxGroupRepo, @@ -41,6 +52,9 @@ public AdministrationService(IRepository fiscalYearRepo, IRepository accountRepo, IRepository auditLogRepo, ISecurityRepository securityRepository, + IFinancialService financialService, + ITaxService taxService, + IMapper mapper, IRepository company = null ) : base(null, generalLedgerSetting, paymentTermRepo, bankRepo) @@ -56,6 +70,9 @@ public AdministrationService(IRepository fiscalYearRepo, _accountRepo = accountRepo; _auditLogRepo = auditLogRepo; _securityRepository = securityRepository; + _financialService = financialService; + _taxService = taxService; + _mapper = mapper; } public ICollection GetAllTaxes(bool includeInActive) @@ -65,19 +82,175 @@ public ICollection GetAllTaxes(bool includeInActive) return query.ToList(); } + public async Task> CreateTaxAsync(Dto.TaxSystem.TaxForCreation taxForCreationDto) + { + var query = from f in _taxRepo.Table + where f.TaxName == taxForCreationDto.TaxName || f.TaxCode == taxForCreationDto.TaxCode + select f; + + if (query.Any()) + { + var message = $"Tax with name {taxForCreationDto.TaxName} or code {taxForCreationDto.TaxCode} already exists"; + return Result.Failure(Error.ValidationError(message)); + } + + var salesTaxAccount = _financialService.GetAccountByAccountCode(taxForCreationDto.SalesAccountId.ToString()); + var purchaseTaxAccount = _financialService.GetAccountByAccountCode(taxForCreationDto.PurchaseAccountId.ToString()); + + var taxEntity = _mapper.Map(taxForCreationDto); + taxEntity.SalesAccountId = salesTaxAccount.Id; + taxEntity.PurchasingAccountId = purchaseTaxAccount.Id; + taxEntity.SalesAccount = salesTaxAccount; + taxEntity.PurchasingAccount = purchaseTaxAccount; + + var taxGroupEntity = AddNewTaxGroup(taxForCreationDto.TaxGroup); + taxEntity.TaxGroupTaxes.Add(new Core.Domain.TaxSystem.TaxGroupTax + { + TaxId = taxEntity.Id, + TaxGroupId = taxGroupEntity.Id, + TaxGroup = taxGroupEntity, + }); + + var itemTaxGroupEntity = AddNewItemTaxGroup(taxForCreationDto.ItemTaxGroup); + taxEntity.ItemTaxGroupTaxes.Add(new Core.Domain.TaxSystem.ItemTaxGroupTax + { + TaxId = taxEntity.Id, + ItemTaxGroupId = itemTaxGroupEntity.Id, + ItemTaxGroup = itemTaxGroupEntity, + }); + + await AddNewTaxAsync(taxEntity); + var taxToReturn = _mapper.Map(taxEntity); + + return Result.Success(taxToReturn); + } + public void AddNewTax(Tax tax) { _taxRepo.Insert(tax); } - public void UpdateTax(Tax tax) + public async Task AddNewTaxAsync(Tax tax) + { + await _taxRepo.InsertAsync(tax); + } + + public TaxGroup AddNewTaxGroup(Dto.TaxSystem.TaxGroup taxGroupDto) + { + var taxGroupEntity = _taxGroupRepo.GetById(taxGroupDto.Id); + if (taxGroupEntity is null) + { + taxGroupEntity = _mapper.Map(taxGroupDto); + _taxGroupRepo.Insert(taxGroupEntity); + } + + return taxGroupEntity; + } + + public ItemTaxGroup AddNewItemTaxGroup(Dto.TaxSystem.ItemTaxGroup itemTaxGroupDto) + { + var itemTaxGroupEntity = _itemTaxGroupRepo.GetById(itemTaxGroupDto.Id); + if (itemTaxGroupEntity is null) + { + itemTaxGroupEntity = _mapper.Map(itemTaxGroupDto); + _itemTaxGroupRepo.Insert(itemTaxGroupEntity); + } + + return itemTaxGroupEntity; + } + + public async Task> EditTaxAsync(Dto.TaxSystem.TaxForUpdate taxForUpdateDto) + { + var taxEntity = _taxService.GetTaxById(taxForUpdateDto.Tax.Id); + if(taxEntity is null) + { + var message = $"Tax with id {taxForUpdateDto.Tax.Id} is not found."; + return Result.Failure(Error.RecordNotFound(message)); + } + + var salesTaxAccount = _financialService.GetAccountByAccountCode(taxForUpdateDto.SalesAccountId.ToString()); + var purchaseTaxAccount = _financialService.GetAccountByAccountCode(taxForUpdateDto.PurchaseAccountId.ToString()); + + _mapper.Map(taxForUpdateDto, taxEntity); + taxEntity.SalesAccountId = salesTaxAccount.Id; + taxEntity.PurchasingAccountId = purchaseTaxAccount.Id; + taxEntity.SalesAccount = salesTaxAccount; + taxEntity.PurchasingAccount = purchaseTaxAccount; + + taxEntity.TaxGroupTaxes.Clear(); + + var taxGroupEntity = AddNewTaxGroup(taxForUpdateDto.TaxGroup); + taxEntity.TaxGroupTaxes.Add(new Core.Domain.TaxSystem.TaxGroupTax + { + TaxId = taxEntity.Id, + TaxGroupId = taxGroupEntity.Id, + TaxGroup = taxGroupEntity, + }); + + taxEntity.ItemTaxGroupTaxes.Clear(); + + var itemTaxGroupEntity = AddNewItemTaxGroup(taxForUpdateDto.ItemTaxGroup); + taxEntity.ItemTaxGroupTaxes.Add(new Core.Domain.TaxSystem.ItemTaxGroupTax + { + TaxId = taxEntity.Id, + ItemTaxGroupId = itemTaxGroupEntity.Id, + ItemTaxGroup = itemTaxGroupEntity + }); + + await UpdateTaxAsync(taxEntity); + var taxToRetun = _mapper.Map(taxEntity); + + return Result.Success(taxToRetun); + } + + public async Task UpdateTaxAsync(Tax tax) + { + await _taxRepo.UpdateAsync(tax); + } + + public async Task> DeleteTaxAsync(int taxId) + { + var tax = _taxRepo.GetById(taxId); + + if(tax is null) + { + var message = $"Tax with id {taxId} not found"; + return Result.Failure(Error.RecordNotFound(message)); + } + + await _taxRepo.DeleteAsync(tax); + + return Result.Success(null); + } + + public async Task> DeleteTaxGroupAsync(int taxGroupId) { - _taxRepo.Update(tax); + var taxGroup = _taxGroupRepo.GetById(taxGroupId); + + if (taxGroup is null) + { + var message = $"TaxGroup with id {taxGroupId} not found"; + return Result.Failure(Error.RecordNotFound(message)); + } + + await _taxGroupRepo.DeleteAsync(taxGroup); + + return Result.Success(null); } - public void DeleteTax(int id) + public async Task> DeleteItemTaxGroupAsync(int itemTaxGroupId) { - throw new System.NotImplementedException(); + var itemTaxGroup = _itemTaxGroupRepo.GetById(itemTaxGroupId); + + if (itemTaxGroup is null) + { + var message = $"ItemTaxGroup with id {itemTaxGroupId} not found"; + return Result.Failure(Error.RecordNotFound(message)); + } + + await _itemTaxGroupRepo.DeleteAsync(itemTaxGroup); + + return Result.Success(null); } public ICollection GetItemTaxGroups(bool includeInActive) @@ -123,7 +296,9 @@ public ICollection GetFinancialYears() public void SaveCompany(Company company) { - if (company.Id == 0) { _company.Insert(company); } + if (company.Id == 0) { + _company.Insert(company); + } else { _company.Update(company); } } diff --git a/src/Services/Administration/IAdministrationService.cs b/src/Services/Administration/IAdministrationService.cs index d478b0a03..f95a19c15 100644 --- a/src/Services/Administration/IAdministrationService.cs +++ b/src/Services/Administration/IAdministrationService.cs @@ -12,6 +12,8 @@ using Core.Domain.Financials; using Core.Domain.Security; using Core.Domain.Auditing; +using Core.Domain.Error; +using System.Threading.Tasks; namespace Services.Administration { @@ -20,9 +22,16 @@ public interface IAdministrationService ICollection GetAllTaxes(bool includeInActive); ICollection GetItemTaxGroups(bool includeInActive); ICollection GetTaxGroups(bool includeInActive); + Task> CreateTaxAsync(Dto.TaxSystem.TaxForCreation taxForCreationDto); void AddNewTax(Tax tax); - void UpdateTax(Tax tax); - void DeleteTax(int id); + Task AddNewTaxAsync(Tax tax); + TaxGroup AddNewTaxGroup(Dto.TaxSystem.TaxGroup taxGroupDto); + ItemTaxGroup AddNewItemTaxGroup(Dto.TaxSystem.ItemTaxGroup itemTaxGroupDto); + Task> EditTaxAsync(Dto.TaxSystem.TaxForUpdate taxForUpdateDto); + Task UpdateTaxAsync(Tax tax); + Task> DeleteTaxAsync(int id); + Task> DeleteTaxGroupAsync(int id); + Task> DeleteItemTaxGroupAsync(int id); void InitializeCompany(); Company GetDefaultCompany(); ICollection GetPaymentTerms(); diff --git a/src/Services/Financial/FinancialService.cs b/src/Services/Financial/FinancialService.cs index bb860e869..a6c1550f8 100644 --- a/src/Services/Financial/FinancialService.cs +++ b/src/Services/Financial/FinancialService.cs @@ -154,6 +154,7 @@ public Account GetAccountByAccountCode(string accountcode) a => a.ParentAccount, a => a.Company) .Where(a => a.AccountCode == accountcode) + //.OrderByDescending(a => a.Id) .FirstOrDefault(); return account; @@ -201,10 +202,11 @@ public bool ValidateGeneralLedgerEntry(GeneralLedgerHeader glEntry) throw new InvalidOperationException("One or more line(s) amount is zero."); var fiscalYear = CurrentFiscalYear(); - if (fiscalYear == null - || !FinancialHelper.InRange(glEntry.Date, fiscalYear.StartDate, fiscalYear.EndDate) - || !FinancialHelper.InRange(DateTime.Now, fiscalYear.StartDate, fiscalYear.EndDate)) - throw new InvalidOperationException("Date is out of range. Must within financial year."); + //TODO: Fix this + // if (fiscalYear == null + // || !FinancialHelper.InRange(glEntry.Date, fiscalYear.StartDate, fiscalYear.EndDate) + // || !FinancialHelper.InRange(DateTime.Now, fiscalYear.StartDate, fiscalYear.EndDate)) + // throw new InvalidOperationException("Date is out of range. Must within financial year."); //var duplicateAccounts = glEntry.GeneralLedgerLines.GroupBy(gl => gl.AccountId).Where(gl => gl.Count() > 1); //if (duplicateAccounts.Count() > 0) @@ -310,6 +312,7 @@ public void AddJournalEntry(JournalEntryHeader journalEntry) return accounts; } + // TODO: This generates an error public ICollection BalanceSheet(DateTime? from = default(DateTime?), DateTime? to = default(DateTime?)) { var assets = from a in _accountRepo.GetAllIncluding(a => a.AccountClass, @@ -509,10 +512,9 @@ public void AddJournalEntry(JournalEntryHeader journalEntry) /// public List> ComputeInputTax(int vendorId, int itemId, decimal quantity, decimal amount, decimal discount) { - decimal taxAmount = 0, amountXquantity = 0, discountAmount = 0, subTotalAmount = 0; + decimal taxAmount, amountXquantity, discountAmount = 0, subTotalAmount; var taxes = new List>(); - var item = _inventoryService.GetItemById(itemId); amountXquantity = amount * quantity; @@ -541,7 +543,7 @@ public List> ComputeInputTax(int vendorId, int itemId /// public List> ComputeOutputTax(int customerId, int itemId, decimal quantity, decimal amount, decimal discount) { - decimal taxAmount = 0, amountXquantity = 0, discountAmount = 0, subTotalAmount = 0; + decimal taxAmount, amountXquantity, discountAmount = 0, subTotalAmount; var taxes = new List>(); @@ -732,11 +734,12 @@ Interest Expense 150 var glSetting = _generalLedgerSettingRepo.Table.FirstOrDefault(); - var journalEntry = new JournalEntryHeader(); - journalEntry.Memo = "Closing entries"; - journalEntry.Date = DateTime.Now; - journalEntry.Posted = false; - journalEntry.VoucherType = JournalVoucherTypes.ClosingEntries; + var journalEntry = new JournalEntryHeader() { + Memo = "Closing entries", + Date = DateTime.Now, + Posted = false, + VoucherType = JournalVoucherTypes.ClosingEntries + }; return journalEntry; } diff --git a/src/Services/Purchasing/PurchasingService.cs b/src/Services/Purchasing/PurchasingService.cs index 800a77d5f..d29dc1672 100644 --- a/src/Services/Purchasing/PurchasingService.cs +++ b/src/Services/Purchasing/PurchasingService.cs @@ -17,6 +17,8 @@ using System.Linq; using System; using System.Threading; +using Microsoft.Extensions.Logging; +using Services.Sales; namespace Services.Purchasing { @@ -25,6 +27,8 @@ public partial class PurchasingService : BaseService, IPurchasingService private readonly IFinancialService _financialService; private readonly IInventoryService _inventoryService; + private readonly ILogger _logger; + private readonly IRepository _purchaseOrderRepo; private readonly IRepository _purchaseOrderLineRepo; private readonly IRepository _purchaseInvoiceRepo; @@ -57,7 +61,8 @@ public PurchasingService(IFinancialService financialService, IRepository paymentTermRepo, IRepository bankRepo, IRepository contactRepo, - IPurchaseOrderRepository purchaseOrderHeaderRepository + IPurchaseOrderRepository purchaseOrderHeaderRepository, + ILogger logger ) : base(sequenceNumberRepo, generalLedgerSettingRepo, paymentTermRepo, bankRepo) { @@ -78,6 +83,7 @@ IPurchaseOrderRepository purchaseOrderHeaderRepository _bankRepo = bankRepo; _purchaseOrderHeaderRepository = purchaseOrderHeaderRepository; _contactRepo = contactRepo; + _logger = logger; } public void AddPurchaseInvoice(PurchaseInvoiceHeader purchaseIvoice, int? purchaseOrderId) @@ -481,7 +487,7 @@ public void SavePurchaseInvoice(PurchaseInvoiceHeader purchaseInvoice, PurchaseO } catch (Exception ex) { - throw ex; + _logger.LogError(ex.Message); } } diff --git a/src/Services/Sales/ISalesService.cs b/src/Services/Sales/ISalesService.cs index 3439e1c27..d4f9d36a1 100644 --- a/src/Services/Sales/ISalesService.cs +++ b/src/Services/Sales/ISalesService.cs @@ -7,8 +7,10 @@ //----------------------------------------------------------------------- using Core.Domain; +using Core.Domain.Error; using Core.Domain.Sales; using System.Collections.Generic; +using System.Threading.Tasks; namespace Services.Sales { @@ -48,6 +50,9 @@ public partial interface ISalesService IEnumerable GetCustomerInvoices(int customerId); SalesQuoteHeader GetSalesQuotationById(int id); void SaveSalesInvoice(SalesInvoiceHeader salesInvoice, SalesOrderHeader salesOrder); + Result CreateSalesInvoice(Dto.Sales.SalesInvoice salesInvoiceDto); + Result UpdateSalesInvoice(Dto.Sales.SalesInvoice salesInvoiceDto); + Task> DeleteSalesInvoiceAsync(int id); void PostSalesInvoice(int invoiceId); Contact GetContacyById(int id); CustomerContact GetCustomerContact(int id); diff --git a/src/Services/Sales/SalesService.cs b/src/Services/Sales/SalesService.cs index cc5b472b5..bc7bc5887 100644 --- a/src/Services/Sales/SalesService.cs +++ b/src/Services/Sales/SalesService.cs @@ -17,6 +17,10 @@ using System; using System.Collections.Generic; using Core.Domain.TaxSystem; +using Microsoft.Extensions.Logging; +using AutoMapper; +using Core.Domain.Error; +using System.Threading.Tasks; namespace Services.Sales { @@ -25,6 +29,9 @@ public partial class SalesService : BaseService, ISalesService private readonly IFinancialService _financialService; private readonly IInventoryService _inventoryService; + private readonly IMapper _mapper; + private readonly ILogger _logger; + private readonly IRepository _salesOrderRepo; private readonly IRepository _salesOrderLineRepo; private readonly IRepository _salesInvoiceRepo; @@ -44,7 +51,7 @@ public partial class SalesService : BaseService, ISalesService private readonly IRepository _taxGroupRepo; private readonly IRepository _salesQuoteRepo; private readonly ISalesOrderRepository _salesOrderRepository; - + public SalesService(IFinancialService financialService, IInventoryService inventoryService, IRepository salesOrderRepo, @@ -65,7 +72,9 @@ public SalesService(IFinancialService financialService, IRepository salesQuoteRepo, ISalesOrderRepository salesOrderRepository, IRepository customerContactRepo, - IRepository vendorContactRepo) + IRepository vendorContactRepo, + ILogger logger, + IMapper mapper) : base(sequenceNumberRepo, generalLedgerSetting, paymentTermRepo, bankRepo) { _financialService = financialService; @@ -89,6 +98,8 @@ public SalesService(IFinancialService financialService, _salesOrderLineRepo = salesOrderLineRepo; _customerContactRepo = customerContactRepo; _vendorContactRepo = vendorContactRepo; + _logger = logger; + _mapper = mapper; } public void AddSalesOrder(SalesOrderHeader salesOrder, bool toSave) @@ -321,6 +332,14 @@ public SalesInvoiceHeader GetSalesInvoiceById(int id) .Where(inv => inv.Id == id) .FirstOrDefault(); + if (invoice != null) { + foreach (var line in invoice.SalesInvoiceLines) + { + line.Item = _itemRepo.GetById(line.ItemId); + line.Measurement = _measurementRepo.GetById(line.MeasurementId); + } + } + return invoice; } @@ -644,10 +663,9 @@ public void SaveContact(Contact contact) } } - catch (Exception e) + catch (Exception ex) { - - throw e; + _logger.LogError(ex.Message); } } @@ -701,9 +719,123 @@ public SalesQuoteHeader GetSalesQuotationById(int id) .Where(q => q.Id == id) .FirstOrDefault(); + if (quotation != null) { + foreach (var line in quotation.SalesQuoteLines) + { + line.Item = _itemRepo.GetById(line.ItemId); + line.Measurement = _measurementRepo.GetById(line.MeasurementId); + } + } + return quotation; } + public Result CreateSalesInvoice(Dto.Sales.SalesInvoice salesInvoiceDto) + { + Core.Domain.Sales.SalesOrderHeader? salesOrder = null; + Core.Domain.Sales.SalesInvoiceHeader? salesInvoice = null; + + if (!salesInvoiceDto.FromSalesOrderId.HasValue) + { + salesOrder = _mapper.Map(salesInvoiceDto); + } + else + { + // your invoice is created from existing (open) sales order. + salesOrder = GetSalesOrderById(salesInvoiceDto.FromSalesOrderId.GetValueOrDefault()); + + if(salesOrder is null) + { + var message = $"Sales order {salesInvoiceDto.FromSalesOrderId} in SalesInvoice not found."; + return Result.Failure(Error.RecordNotFound(message)); + } + } + + salesInvoice = _mapper.Map(salesInvoiceDto); + + foreach(var invoiceLine in salesInvoice.SalesInvoiceLines) + { + if(invoiceLine.SalesOrderLineId == 0) + { + salesOrder.SalesOrderLines.Add(invoiceLine.SalesOrderLine); + invoiceLine.SalesOrderLineId = invoiceLine.SalesOrderLine.Id; + } + } + + _logger.LogInformation("SaveSalesInvoice API " + salesInvoice.CustomerId); + + SaveSalesInvoice(salesInvoice, salesOrder); + + return Result.Success(salesInvoiceDto); + } + + public Result UpdateSalesInvoice(Dto.Sales.SalesInvoice salesInvoiceDto) + { + Core.Domain.Sales.SalesInvoiceHeader? salesInvoice = null; + Core.Domain.Sales.SalesOrderHeader? salesOrder = null; + + salesInvoice = GetSalesInvoiceById(salesInvoiceDto.Id); + + if(salesInvoice is null) + { + var message = $"Sales invoice {salesInvoiceDto.Id} not found."; + return Result.Failure(Error.RecordNotFound(message)); + } + + if (salesInvoice.GeneralLedgerHeaderId.HasValue) + throw new Exception("Invoice is already posted. Update is not allowed."); + + _mapper.Map(salesInvoiceDto, salesInvoice); + + int existingOrderLineId = salesInvoice.SalesInvoiceLines.FirstOrDefault().SalesOrderLineId ??= 0; + foreach (var invoiceLine in salesInvoice.SalesInvoiceLines!) + { + salesOrder = GetSalesOrderLineById(invoiceLine!.SalesOrderLineId ??= 0).SalesOrderHeader; + + if (invoiceLine.Id == 0) + { + // use the last value of existingLine + salesOrder = GetSalesOrderLineById(existingOrderLineId).SalesOrderHeader; + salesOrder.SalesOrderLines.Add(invoiceLine.SalesOrderLine); + } + else + { + // TODO: Udpate Existing SalesOrderLine with SalesInvoiceLine. + invoiceLine.SalesOrderLine = GetSalesOrderLineById(invoiceLine.SalesOrderLineId.GetValueOrDefault()); + } + } + + var deleted = (from line in salesInvoice.SalesInvoiceLines + where !salesInvoiceDto.SalesInvoiceLines.Any(x => x.Id == line.Id) + select line).ToList(); + + foreach (var line in deleted) + { + salesInvoice.SalesInvoiceLines.Remove(line); + } + + _logger.LogInformation("SaveSalesInvoice API " + salesInvoice.CustomerId); + + SaveSalesInvoice(salesInvoice, salesOrder); + + return Result.Success(null); + } + + public async Task> DeleteSalesInvoiceAsync(int id) + { + var salesInvoice = GetSalesInvoiceById(id); + + if (salesInvoice is null) + { + var message = $"Sales invoice {id} not found."; + return Result.Failure(Error.RecordNotFound(message)); + } + + await _salesInvoiceRepo.DeleteAsync(salesInvoice); + + return Result.Success(null); + } + public void SaveSalesInvoice(SalesInvoiceHeader salesInvoice, SalesOrderHeader salesOrder) { // This method should be in a single transaction. when one fails, roll back all changes. @@ -730,6 +862,7 @@ public void SaveSalesInvoice(SalesInvoiceHeader salesInvoice, SalesOrderHeader s } else { + _logger.LogInformation("Invoice " + salesInvoice.CustomerId + " is being updated."); _salesInvoiceRepo.Update(salesInvoice); } @@ -737,7 +870,7 @@ public void SaveSalesInvoice(SalesInvoiceHeader salesInvoice, SalesOrderHeader s } catch (Exception ex) { - throw ex; + _logger.LogError(ex.Message); } } diff --git a/src/Services/Services.csproj b/src/Services/Services.csproj index 109f4d790..2d740c257 100644 --- a/src/Services/Services.csproj +++ b/src/Services/Services.csproj @@ -1,12 +1,13 @@  - - netstandard2.1 + net9.0 Library - + + + + - \ No newline at end of file diff --git a/src/Services/TaxSystem/ITaxService.cs b/src/Services/TaxSystem/ITaxService.cs index 183b0e72b..2e3e9a40a 100644 --- a/src/Services/TaxSystem/ITaxService.cs +++ b/src/Services/TaxSystem/ITaxService.cs @@ -6,6 +6,7 @@ namespace Services.TaxSystem { public interface ITaxService { + Core.Domain.TaxSystem.Tax GetTaxById(int taxId); IEnumerable GetTaxes(bool includeInActive = false); IEnumerable GetTaxGroups(); IEnumerable GetItemTaxGroups(); diff --git a/src/Services/TaxSystem/TaxService.cs b/src/Services/TaxSystem/TaxService.cs index a857734a5..b03b83168 100644 --- a/src/Services/TaxSystem/TaxService.cs +++ b/src/Services/TaxSystem/TaxService.cs @@ -43,6 +43,18 @@ public TaxService(IRepository vendorRepo, _taxGroupTaxRepo = taxGroupTaxRepo; } + public Tax GetTaxById(int taxId) + { + var taxEntity = _taxRepo + .GetAllIncluding(s => s.SalesAccount, p => p.PurchasingAccount, tgt => tgt.TaxGroupTaxes, itgt => itgt.ItemTaxGroupTaxes) + .FirstOrDefault(tax => tax.Id == taxId); + + if(taxEntity is null) + throw new NotImplementedException("Tax not found"); + + return taxEntity; + } + public IEnumerable GetTaxes(bool includeInActive = false) { var taxes = _taxRepo diff --git a/src/src.AppHost/Program.cs b/src/src.AppHost/Program.cs new file mode 100644 index 000000000..2b9b483c9 --- /dev/null +++ b/src/src.AppHost/Program.cs @@ -0,0 +1,25 @@ +using System.Reflection; +using Google.Protobuf.WellKnownTypes; + +var builder = DistributedApplication.CreateBuilder(args); + +var sqlServer = builder.AddSqlServer("gdb-sql-server") + .AddDatabase("gdb-db"); + +// read environment variable for connection string +var apiService = builder.AddProject("api") + .WithReference(sqlServer) + .WithHttpEndpoint(port: 8001) + .WaitFor(sqlServer); + +builder.AddProject("mvc") + .WithHttpEndpoint(port: 8000) + .WithReference(apiService) + .WaitFor(apiService); + +builder.AddProject("migrations") + .WithReference(sqlServer) + .WaitFor(sqlServer); + +builder.Build().Run(); + diff --git a/src/src.AppHost/Properties/launchSettings.json b/src/src.AppHost/Properties/launchSettings.json new file mode 100644 index 000000000..2b3d5596f --- /dev/null +++ b/src/src.AppHost/Properties/launchSettings.json @@ -0,0 +1,29 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "profiles": { + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "applicationUrl": "https://localhost:17118;http://localhost:15251", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development", + "DOTNET_ENVIRONMENT": "Development", + "DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:21083", + "DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:22106" + } + }, + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "applicationUrl": "http://localhost:15251", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development", + "DOTNET_ENVIRONMENT": "Development", + "DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:19070", + "DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:20256" + } + } + } +} diff --git a/src/src.AppHost/appsettings.Development.json b/src/src.AppHost/appsettings.Development.json new file mode 100644 index 000000000..0c208ae91 --- /dev/null +++ b/src/src.AppHost/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/src/src.AppHost/appsettings.json b/src/src.AppHost/appsettings.json new file mode 100644 index 000000000..31c092aa4 --- /dev/null +++ b/src/src.AppHost/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning", + "Aspire.Hosting.Dcp": "Warning" + } + } +} diff --git a/src/src.AppHost/src.AppHost.csproj b/src/src.AppHost/src.AppHost.csproj new file mode 100644 index 000000000..e66dd9a19 --- /dev/null +++ b/src/src.AppHost/src.AppHost.csproj @@ -0,0 +1,25 @@ + + + + + + Exe + net9.0 + enable + enable + true + 13ebf7e1-4bc3-4178-925c-d2b16f2f0006 + + + + + + + + + + + + + + diff --git a/src/src.ServiceDefaults/Extensions.cs b/src/src.ServiceDefaults/Extensions.cs new file mode 100644 index 000000000..ce94dc2c4 --- /dev/null +++ b/src/src.ServiceDefaults/Extensions.cs @@ -0,0 +1,111 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Diagnostics.HealthChecks; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Diagnostics.HealthChecks; +using Microsoft.Extensions.Logging; +using OpenTelemetry; +using OpenTelemetry.Metrics; +using OpenTelemetry.Trace; + +namespace Microsoft.Extensions.Hosting; + +// Adds common .NET Aspire services: service discovery, resilience, health checks, and OpenTelemetry. +// This project should be referenced by each service project in your solution. +// To learn more about using this project, see https://aka.ms/dotnet/aspire/service-defaults +public static class Extensions +{ + public static IHostApplicationBuilder AddServiceDefaults(this IHostApplicationBuilder builder) + { + builder.ConfigureOpenTelemetry(); + + builder.AddDefaultHealthChecks(); + + builder.Services.AddServiceDiscovery(); + + builder.Services.ConfigureHttpClientDefaults(http => + { + // Turn on resilience by default + http.AddStandardResilienceHandler(); + + // Turn on service discovery by default + http.AddServiceDiscovery(); + }); + + return builder; + } + + public static IHostApplicationBuilder ConfigureOpenTelemetry(this IHostApplicationBuilder builder) + { + builder.Logging.AddOpenTelemetry(logging => + { + logging.IncludeFormattedMessage = true; + logging.IncludeScopes = true; + }); + + builder.Services.AddOpenTelemetry() + .WithMetrics(metrics => + { + metrics.AddAspNetCoreInstrumentation() + .AddHttpClientInstrumentation() + .AddRuntimeInstrumentation(); + }) + .WithTracing(tracing => + { + tracing.AddAspNetCoreInstrumentation() + // Uncomment the following line to enable gRPC instrumentation (requires the OpenTelemetry.Instrumentation.GrpcNetClient package) + //.AddGrpcClientInstrumentation() + .AddHttpClientInstrumentation(); + }); + + builder.AddOpenTelemetryExporters(); + + return builder; + } + + private static IHostApplicationBuilder AddOpenTelemetryExporters(this IHostApplicationBuilder builder) + { + var useOtlpExporter = !string.IsNullOrWhiteSpace(builder.Configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]); + + if (useOtlpExporter) + { + builder.Services.AddOpenTelemetry().UseOtlpExporter(); + } + + // Uncomment the following lines to enable the Azure Monitor exporter (requires the Azure.Monitor.OpenTelemetry.AspNetCore package) + //if (!string.IsNullOrEmpty(builder.Configuration["APPLICATIONINSIGHTS_CONNECTION_STRING"])) + //{ + // builder.Services.AddOpenTelemetry() + // .UseAzureMonitor(); + //} + + return builder; + } + + public static IHostApplicationBuilder AddDefaultHealthChecks(this IHostApplicationBuilder builder) + { + builder.Services.AddHealthChecks() + // Add a default liveness check to ensure app is responsive + .AddCheck("self", () => HealthCheckResult.Healthy(), ["live"]); + + return builder; + } + + public static WebApplication MapDefaultEndpoints(this WebApplication app) + { + // Adding health checks endpoints to applications in non-development environments has security implications. + // See https://aka.ms/dotnet/aspire/healthchecks for details before enabling these endpoints in non-development environments. + if (app.Environment.IsDevelopment()) + { + // All health checks must pass for app to be considered ready to accept traffic after starting + app.MapHealthChecks("/health"); + + // Only health checks tagged with the "live" tag must pass for app to be considered alive + app.MapHealthChecks("/alive", new HealthCheckOptions + { + Predicate = r => r.Tags.Contains("live") + }); + } + + return app; + } +} diff --git a/src/src.ServiceDefaults/src.ServiceDefaults.csproj b/src/src.ServiceDefaults/src.ServiceDefaults.csproj new file mode 100644 index 000000000..eeda27dd4 --- /dev/null +++ b/src/src.ServiceDefaults/src.ServiceDefaults.csproj @@ -0,0 +1,22 @@ + + + + net9.0 + enable + enable + true + + + + + + + + + + + + + + + diff --git a/test/Module.Tests/Module.Tests.csproj b/test/Module.Tests/Module.Tests.csproj index 9d04ab11c..55309c1c9 100644 --- a/test/Module.Tests/Module.Tests.csproj +++ b/test/Module.Tests/Module.Tests.csproj @@ -6,9 +6,12 @@ - - - + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + diff --git a/test/SampleModules/SampleNetStandard20/SampleNetStandard20.csproj b/test/SampleModules/SampleNetStandard20/SampleNetStandard20.csproj index 18d638898..96412b833 100644 --- a/test/SampleModules/SampleNetStandard20/SampleNetStandard20.csproj +++ b/test/SampleModules/SampleNetStandard20/SampleNetStandard20.csproj @@ -8,9 +8,9 @@ - - - + + +