diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 10d527376b..9b4b1dca61 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -3,7 +3,7 @@ "hostRequirements": { "cpus": 4 }, - "onCreateCommand": "wget https://download.visualstudio.microsoft.com/download/pr/5226a5fa-8c0b-474f-b79a-8984ad7c5beb/3113ccbf789c9fd29972835f0f334b7a/dotnet-sdk-8.0.100-linux-x64.tar.gz -O $HOME/dotnet.tar.gz && export DOTNET_ROOT=$HOME/.dotnet && mkdir -p \"$DOTNET_ROOT\" && tar zxf $HOME/dotnet.tar.gz -C \"$DOTNET_ROOT\" && export PATH=$DOTNET_ROOT:$DOTNET_ROOT/tools:$PATH && dotnet dev-certs https --trust && dotnet build src/BlazorUI/Demo/Client/Web/Bit.BlazorUI.Demo.Client.Web.csproj && dotnet build src/Websites/Platform/src/Bit.Websites.Platform.Client/Bit.Websites.Platform.Client.csproj -t:BeforeBuildTasks --no-restore && dotnet build src/Websites/Sales/src/Bit.Websites.Sales.Web/Bit.Websites.Sales.Web.csproj -t:BeforeBuildTasks --no-restore && dotnet build src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Core/Boilerplate.Client.Core.csproj -t:BeforeBuildTasks --no-restore", + "onCreateCommand": "wget https://download.visualstudio.microsoft.com/download/pr/5226a5fa-8c0b-474f-b79a-8984ad7c5beb/3113ccbf789c9fd29972835f0f334b7a/dotnet-sdk-8.0.100-linux-x64.tar.gz -O $HOME/dotnet.tar.gz && export DOTNET_ROOT=$HOME/.dotnet && mkdir -p \"$DOTNET_ROOT\" && tar zxf $HOME/dotnet.tar.gz -C \"$DOTNET_ROOT\" && export PATH=$DOTNET_ROOT:$DOTNET_ROOT/tools:$PATH && dotnet dev-certs https --trust && dotnet build src/BlazorUI/Demo/Client/Web/Bit.BlazorUI.Demo.Client.Web.csproj && dotnet build src/Websites/Platform/src/Bit.Websites.Platform.Client/Bit.Websites.Platform.Client.csproj -t:BeforeBuildTasks --no-restore && dotnet build src/Websites/Sales/src/Bit.Websites.Sales.Client/Bit.Websites.Sales.Client.csproj -t:BeforeBuildTasks --no-restore && dotnet build src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Core/Boilerplate.Client.Core.csproj -t:BeforeBuildTasks --no-restore", "waitFor": "onCreateCommand", "customizations": { "codespaces": { diff --git a/.github/workflows/sales.website.cd.yml b/.github/workflows/sales.website.cd.yml index 193a69ad20..1e9c8737d9 100644 --- a/.github/workflows/sales.website.cd.yml +++ b/.github/workflows/sales.website.cd.yml @@ -1,7 +1,6 @@ name: Sales Website CD env: - WEB_APP_DEPLOYMENT_TYPE: 'SSR' APP_SERVICE_NAME: 'bitservices' on: @@ -14,8 +13,8 @@ permissions: jobs: - build_blazor_api_wasm: - name: build blazor api + web assembly + build_api_blazor: + name: build api + blazor runs-on: ubuntu-22.04 steps: @@ -27,25 +26,15 @@ jobs: uses: actions/setup-dotnet@v3 with: global-json-file: src/global.json - - - name: Switch to blazor web assembly - run: sed -i 's/Microsoft.NET.Sdk.Web/Microsoft.NET.Sdk.BlazorWebAssembly/g' src/Websites/Sales/src/Bit.Websites.Sales.Web/Bit.Websites.Sales.Web.csproj - + - name: Install wasm run: cd src && dotnet workload install wasm-tools wasm-experimental - - - name: Update appsettings.json api server address - uses: microsoft/variable-substitution@v1 - with: - files: 'src/Websites/Sales/src/Bit.Websites.Sales.Web/appsettings.json' - env: - ApiServerAddress: 'api/' - name: Generate CSS/JS files - run: dotnet build src/Websites/Sales/src/Bit.Websites.Sales.Web/Bit.Websites.Sales.Web.csproj -t:BeforeBuildTasks --no-restore + run: dotnet build src/Websites/Sales/src/Bit.Websites.Sales.Client/Bit.Websites.Sales.Client.csproj -t:BeforeBuildTasks --no-restore - name: Publish - run: dotnet publish src/Websites/Sales/src/Bit.Websites.Sales.Api/Bit.Websites.Sales.Api.csproj -p:BlazorMode=BlazorWebAssembly -p:WebAppDeploymentType="${{ env.WEB_APP_DEPLOYMENT_TYPE }}" -p:Configuration=Release --self-contained -r linux-x64 -o api-web + run: dotnet publish src/Websites/Sales/src/Bit.Websites.Sales.Server/Bit.Websites.Sales.Server.csproj -p:Configuration=Release --self-contained -r linux-x64 -o api-web - name: Upload api-web artifact uses: actions/upload-artifact@v3 @@ -53,9 +42,9 @@ jobs: name: api-web-bundle path: api-web - deploy_blazor_api_wasm: - name: deploy blazor api + web assembly - needs: build_blazor_api_wasm + deploy_api_blazor: + name: deploy api + blazor + needs: build_api_blazor runs-on: ubuntu-22.04 environment: name: 'production' diff --git a/src/Bit-CI.sln b/src/Bit-CI.sln index 8ed2c2c2f5..f206464eb3 100644 --- a/src/Bit-CI.sln +++ b/src/Bit-CI.sln @@ -139,11 +139,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bit.BlazorUI.Assets", "Blaz EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bit.BlazorUI.Icons", "BlazorUI\Bit.BlazorUI.Icons\Bit.BlazorUI.Icons.csproj", "{6B5C3E91-47F9-4DEE-B74B-20ED2D24585A}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bit.Websites.Sales.Api", "Websites\Sales\src\Bit.Websites.Sales.Api\Bit.Websites.Sales.Api.csproj", "{090DDD5F-6BB9-46C2-B81E-E9DF384721A5}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bit.Websites.Sales.Server", "Websites\Sales\src\Bit.Websites.Sales.Server\Bit.Websites.Sales.Server.csproj", "{090DDD5F-6BB9-46C2-B81E-E9DF384721A5}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bit.Websites.Sales.Shared", "Websites\Sales\src\Bit.Websites.Sales.Shared\Bit.Websites.Sales.Shared.csproj", "{01078AA6-DE42-46A4-B541-E019DDAE54AD}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bit.Websites.Sales.Web", "Websites\Sales\src\Bit.Websites.Sales.Web\Bit.Websites.Sales.Web.csproj", "{756CB468-1026-43D6-B58C-4234A77EAD7A}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bit.Websites.Sales.Client", "Websites\Sales\src\Bit.Websites.Sales.Client\Bit.Websites.Sales.Client.csproj", "{756CB468-1026-43D6-B58C-4234A77EAD7A}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bit.Websites.Platform.Shared", "Websites\Platform\src\Bit.Websites.Platform.Shared\Bit.Websites.Platform.Shared.csproj", "{32C64C9A-2A6A-4C87-9307-DC370BCD695C}" EndProject diff --git a/src/Templates/BlazorWeb/Bit.BlazorWeb/src/BlazorWeb.Server/Components/App.razor b/src/Templates/BlazorWeb/Bit.BlazorWeb/src/BlazorWeb.Server/Components/App.razor index 556e08e8ae..650f871437 100644 --- a/src/Templates/BlazorWeb/Bit.BlazorWeb/src/BlazorWeb.Server/Components/App.razor +++ b/src/Templates/BlazorWeb/Bit.BlazorWeb/src/BlazorWeb.Server/Components/App.razor @@ -1,6 +1,5 @@ @*+:cnd:noEmit*@ @using BlazorWeb.Client.Services -@attribute [StreamRendering(true)] @@ -29,12 +28,15 @@ - - - - @*#if (sample == "AdminPanel")*@ - - @*#endif*@ + @if (HttpContext.Request.IsCrawlerClient() is false) + { + + + + @*#if (sample == "AdminPanel")*@ + + @*#endif*@ + } diff --git a/src/Templates/BlazorWeb/Bit.BlazorWeb/src/BlazorWeb.Server/Components/App.razor.cs b/src/Templates/BlazorWeb/Bit.BlazorWeb/src/BlazorWeb.Server/Components/App.razor.cs new file mode 100644 index 0000000000..cf7060a741 --- /dev/null +++ b/src/Templates/BlazorWeb/Bit.BlazorWeb/src/BlazorWeb.Server/Components/App.razor.cs @@ -0,0 +1,9 @@ +using Microsoft.AspNetCore.Components; + +namespace BlazorWeb.Server.Components; + +[StreamRendering(enabled: true)] +public partial class App +{ + [CascadingParameter] HttpContext HttpContext { get; set; } = default!; +} diff --git a/src/Templates/BlazorWeb/Bit.BlazorWeb/src/BlazorWeb.Server/Extensions/HttpRequestExtensions.cs b/src/Templates/BlazorWeb/Bit.BlazorWeb/src/BlazorWeb.Server/Extensions/HttpRequestExtensions.cs index b8d735e228..12760a7e32 100644 --- a/src/Templates/BlazorWeb/Bit.BlazorWeb/src/BlazorWeb.Server/Extensions/HttpRequestExtensions.cs +++ b/src/Templates/BlazorWeb/Bit.BlazorWeb/src/BlazorWeb.Server/Extensions/HttpRequestExtensions.cs @@ -18,7 +18,7 @@ public static string GetBaseUrl(this HttpRequest req) return uriBuilder.Uri.AbsoluteUri; } - public static bool ShouldRenderStaticMode(this HttpRequest request) + public static bool IsCrawlerClient(this HttpRequest request) { var agent = GetLoweredUserAgent(request); diff --git a/src/Websites/Careers/.editorconfig b/src/Websites/Careers/.editorconfig new file mode 100644 index 0000000000..09b151e99d --- /dev/null +++ b/src/Websites/Careers/.editorconfig @@ -0,0 +1,124 @@ +# To learn more about .editorconfig see https://aka.ms/editorconfigdocs +############################### +# Core EditorConfig Options # +############################### +# All files +[*] +indent_style = space +indent_size = 4 +# Code files +[*.{cs,csx,vb,vbx}] +insert_final_newline = true +charset = utf-8-bom +############################### +# .NET Coding Conventions # +############################### +[*.{cs,vb}] +# Organize usings +dotnet_sort_system_directives_first = true +# this. preferences +dotnet_style_qualification_for_field = false:silent +dotnet_style_qualification_for_property = false:silent +dotnet_style_qualification_for_method = false:silent +dotnet_style_qualification_for_event = false:silent +# Language keywords vs BCL types preferences +dotnet_style_predefined_type_for_locals_parameters_members = true:silent +dotnet_style_predefined_type_for_member_access = true:silent +# Parentheses preferences +dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent +dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent +dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent +dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent +# Modifier preferences +dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent +dotnet_style_readonly_field = true:suggestion +# Expression-level preferences +dotnet_style_object_initializer = true:suggestion +dotnet_style_collection_initializer = true:suggestion +dotnet_style_explicit_tuple_names = true:suggestion +dotnet_style_null_propagation = true:suggestion +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:silent +dotnet_style_prefer_inferred_tuple_names = true:suggestion +dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion +dotnet_style_prefer_auto_properties = true:silent +dotnet_style_prefer_conditional_expression_over_assignment = true:silent +dotnet_style_prefer_conditional_expression_over_return = true:silent +############################### +# Naming Conventions # +############################### +# Style Definitions +dotnet_naming_style.pascal_case_style.capitalization = pascal_case +# Use PascalCase for constant fields +dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields +dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style +dotnet_naming_symbols.constant_fields.applicable_kinds = field +dotnet_naming_symbols.constant_fields.applicable_accessibilities = * +dotnet_naming_symbols.constant_fields.required_modifiers = const +############################### +# C# Coding Conventions # +############################### +[*.cs] +# var preferences +csharp_style_namespace_declarations = file_scoped:warning +csharp_style_var_for_built_in_types = true:silent +csharp_style_var_when_type_is_apparent = true:silent +csharp_style_var_elsewhere = true:silent +# Expression-bodied members +csharp_style_expression_bodied_methods = false:silent +csharp_style_expression_bodied_constructors = false:silent +csharp_style_expression_bodied_operators = false:silent +csharp_style_expression_bodied_properties = true:silent +csharp_style_expression_bodied_indexers = true:silent +csharp_style_expression_bodied_accessors = true:silent +# Pattern matching preferences +csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion +csharp_style_pattern_matching_over_as_with_null_check = true:suggestion +# Null-checking preferences +csharp_style_throw_expression = true:suggestion +csharp_style_conditional_delegate_call = true:suggestion +# Modifier preferences +csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion +# Expression-level preferences +csharp_prefer_braces = true:silent +csharp_style_deconstructed_variable_declaration = true:suggestion +csharp_prefer_simple_default_expression = true:suggestion +csharp_style_pattern_local_over_anonymous_function = true:suggestion +csharp_style_inlined_variable_declaration = true:suggestion +############################### +# C# Formatting Rules # +############################### +# New line preferences +csharp_new_line_before_open_brace = all +csharp_new_line_before_else = true +csharp_new_line_before_catch = true +csharp_new_line_before_finally = true +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_members_in_anonymous_types = true +csharp_new_line_between_query_expression_clauses = true +# Indentation preferences +csharp_indent_case_contents = true +csharp_indent_switch_labels = true +csharp_indent_labels = flush_left +# Space preferences +csharp_space_after_cast = false +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_between_method_declaration_parameter_list_parentheses = false +csharp_space_between_parentheses = false +csharp_space_before_colon_in_inheritance_clause = true +csharp_space_after_colon_in_inheritance_clause = true +csharp_space_around_binary_operators = before_and_after +csharp_space_between_method_declaration_empty_parameter_list_parentheses = false +csharp_space_between_method_call_name_and_opening_parenthesis = false +csharp_space_between_method_call_empty_parameter_list_parentheses = false +# Wrapping preferences +csharp_preserve_single_line_statements = true +csharp_preserve_single_line_blocks = true +############################### +# VB Coding Conventions # +############################### +[*.vb] +# Modifier preferences +visual_basic_preferred_modifier_order = Partial,Default,Private,Protected,Public,Friend,NotOverridable,Overridable,MustOverride,Overloads,Overrides,MustInherit,NotInheritable,Static,Shared,Shadows,ReadOnly,WriteOnly,Dim,Const,WithEvents,Widening,Narrowing,Custom,Async:suggestion diff --git a/src/Websites/Careers/.gitignore b/src/Websites/Careers/.gitignore index 34f469d42f..d94eda34b5 100644 --- a/src/Websites/Careers/.gitignore +++ b/src/Websites/Careers/.gitignore @@ -213,6 +213,9 @@ ModelManifest.xml # VS Code .vscode +# .NET Meteor +.meteor + # Rider .idea @@ -222,6 +225,11 @@ profile.arm.json *.map *Resource.designer.cs /**/*.css +custom.aprof + +/src/Server/Api/Attachments/**/*.* + +/src/Bit.Websites.Careers.Client/Scripts/app*.js +/src/Bit.Websites.Careers.Client/wwwroot/scripts/app*.js -/src/Bit.Websites.Careers.Web/Scripts/app*.js -/src/Bit.Websites.Careers.Web/wwwroot/scripts/app*.js +/src/Bit.Websites.Careers.Server/Bit.Websites.CareersDb.db* \ No newline at end of file diff --git a/src/Websites/Careers/Bit.Websites.Careers.sln b/src/Websites/Careers/Bit.Websites.Careers.sln index 55da2460f9..6a7798201d 100644 --- a/src/Websites/Careers/Bit.Websites.Careers.sln +++ b/src/Websites/Careers/Bit.Websites.Careers.sln @@ -1,19 +1,21 @@ + Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 -VisualStudioVersion = 17.0.31611.283 +VisualStudioVersion = 17.8.34302.71 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".SolutionItems", ".SolutionItems", "{5CF43F76-BB71-4B5B-B4DF-1C753E042A8F}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".SolutionItems", ".SolutionItems", "{07D3DE94-9EB8-41FE-8888-0A483D30EBFD}" ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig .gitignore = .gitignore + Clean.bat = Clean.bat src\Directory.Build.props = src\Directory.Build.props - README.md = README.md EndProjectSection EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bit.Websites.Careers.Api", "src\Bit.Websites.Careers.Api\Bit.Websites.Careers.Api.csproj", "{87A052C0-DF5B-4560-960C-3B1D31EC2792}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bit.Websites.Careers.Shared", "src\Bit.Websites.Careers.Shared\Bit.Websites.Careers.Shared.csproj", "{7B577D88-492D-4B13-8B79-55BA13B51EE4}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bit.Websites.Careers.Shared", "src\Bit.Websites.Careers.Shared\Bit.Websites.Careers.Shared.csproj", "{C7234277-F4B8-4B2B-9C75-BDE54A59B1A1}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bit.Websites.Careers.Server", "src\Bit.Websites.Careers.Server\Bit.Websites.Careers.Server.csproj", "{03920E8A-DB33-4239-BCD1-7EE3ECC6E19B}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bit.Websites.Careers.Web", "src\Bit.Websites.Careers.Web\Bit.Websites.Careers.Web.csproj", "{91ABA16B-4583-43F0-94DF-6239586352CD}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bit.Websites.Careers.Client", "src\Bit.Websites.Careers.Client\Bit.Websites.Careers.Client.csproj", "{2B84944A-F323-4F0D-9D70-7FF99B0F7EA7}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -21,23 +23,23 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {87A052C0-DF5B-4560-960C-3B1D31EC2792}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {87A052C0-DF5B-4560-960C-3B1D31EC2792}.Debug|Any CPU.Build.0 = Debug|Any CPU - {87A052C0-DF5B-4560-960C-3B1D31EC2792}.Release|Any CPU.ActiveCfg = Release|Any CPU - {87A052C0-DF5B-4560-960C-3B1D31EC2792}.Release|Any CPU.Build.0 = Release|Any CPU - {C7234277-F4B8-4B2B-9C75-BDE54A59B1A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C7234277-F4B8-4B2B-9C75-BDE54A59B1A1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C7234277-F4B8-4B2B-9C75-BDE54A59B1A1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C7234277-F4B8-4B2B-9C75-BDE54A59B1A1}.Release|Any CPU.Build.0 = Release|Any CPU - {91ABA16B-4583-43F0-94DF-6239586352CD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {91ABA16B-4583-43F0-94DF-6239586352CD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {91ABA16B-4583-43F0-94DF-6239586352CD}.Release|Any CPU.ActiveCfg = Release|Any CPU - {91ABA16B-4583-43F0-94DF-6239586352CD}.Release|Any CPU.Build.0 = Release|Any CPU + {7B577D88-492D-4B13-8B79-55BA13B51EE4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7B577D88-492D-4B13-8B79-55BA13B51EE4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7B577D88-492D-4B13-8B79-55BA13B51EE4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7B577D88-492D-4B13-8B79-55BA13B51EE4}.Release|Any CPU.Build.0 = Release|Any CPU + {03920E8A-DB33-4239-BCD1-7EE3ECC6E19B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {03920E8A-DB33-4239-BCD1-7EE3ECC6E19B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {03920E8A-DB33-4239-BCD1-7EE3ECC6E19B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {03920E8A-DB33-4239-BCD1-7EE3ECC6E19B}.Release|Any CPU.Build.0 = Release|Any CPU + {2B84944A-F323-4F0D-9D70-7FF99B0F7EA7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2B84944A-F323-4F0D-9D70-7FF99B0F7EA7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2B84944A-F323-4F0D-9D70-7FF99B0F7EA7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2B84944A-F323-4F0D-9D70-7FF99B0F7EA7}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {61F7FB11-1E47-470C-91E2-47F8143E1572} + SolutionGuid = {62EABCA9-B5C9-489A-B101-38E38ACEDC1E} EndGlobalSection EndGlobal diff --git a/src/Websites/Careers/Clean.bat b/src/Websites/Careers/Clean.bat index ba7402ad9d..52aa2b50c5 100644 --- a/src/Websites/Careers/Clean.bat +++ b/src/Websites/Careers/Clean.bat @@ -1,16 +1,16 @@ -:: This batch script is designed for comprehensive cleaning of your project by deleting unnecessary files. -:: It's crucial to close any Integrated Development Environment (IDE), such as Visual Studio, etc., before executing this script to prevent any conflicts or loss of unsaved data. -:: Please note that the commands included in this script are specifically tailored for the Windows +:: This batch script cleans your project by deleting unnecessary files. +:: It is important to close any IDEs, such as Visual Studio, before running this script to prevent conflicts or data loss. +:: The commands in this script are specifically designed for Windows. -:: Delete css,js and source maps files if not tracked in git +:: Deletes CSS, JS, and source map files that are not tracked in Git. powershell -Command "[string]$trackedFiles = git ls-files; Get-ChildItem -Include *.css,*.min.css,*.js,*.min.js,*.map -Recurse | ForEach-Object { if ($trackedFiles -NotMatch $_.Name) { Remove-Item -Recurse -Path $_ -Confirm:$false -Force }}" -:: Runs dotnet clean for each csproj file +:: Runs the dotnet clean command for each .csproj file. powershell -Command "Get-ChildItem -Include *.csproj -Recurse | ForEach-Object { dotnet clean $_.FullName }" -:: Delete specified files & folders +:: Deletes the specified files and folders. powershell -Command "Get-ChildItem -Include *.csproj.user,Resources.designer.cs,bin,obj,node_modules,Packages,TestResults,AppPackages,.meteor -Recurse | ForEach-Object { Remove-Item -Recurse -Path $_ -Confirm:$false -Force }" FOR /d /r . %%d IN (.vs) DO @IF EXIST "%%d" rd /s /q "%%d" -:: Delete empty directories +:: Deletes empty directories. powershell -Command "Get-ChildItem -Recurse | Where-Object { $_.PSIsContainer -and @(Get-ChildItem -Lit $_.FullName).Count -eq 0 } | Remove-Item -Confirm:$false -Force" \ No newline at end of file diff --git a/src/Websites/Careers/Clean.sh b/src/Websites/Careers/Clean.sh index fe004842e6..04061b11a9 100644 --- a/src/Websites/Careers/Clean.sh +++ b/src/Websites/Careers/Clean.sh @@ -1,23 +1,23 @@ #!/bin/bash -# This batch script is designed for comprehensive cleaning of your project by deleting unnecessary files. -# It's crucial to close any Integrated Development Environment (IDE), such as vs code, etc., before executing this script to prevent any conflicts or loss of unsaved data. -# Please note that the commands included in this script are specifically tailored for the Linux/macOS +# This batch script cleans your project by deleting unnecessary files. +# It is important to close any IDEs, such as vs for mac, before running this script to prevent conflicts or data loss. +# The commands in this script are specifically designed for macOS/Linux. -# Runs dotnet clean for each csproj file +# Runs the dotnet clean command for each .csproj file. for csproj in $(find . -name '*.csproj'); do dotnet clean $csproj done -# Delete specified directories +# Deletes specified directories for dir in $(find . -type d \( -name "bin" -o -name "obj" -o -name "node_modules" -o -name "Packages" -o -name ".vs" -o -name "TestResults" -o -name "AppPackages" -o -name ".meteor" \)); do rm -rf $dir done -# Delete specified files +# Deletes specified files for file in $(find . -type f \( -name "*.csproj.user" -o -name "Resources.designer.cs" -o -name "*.css" -o -name "*.min.css" -o -name "*.js" -o -name "*.min.js" -o -name "*.map" \)); do rm -f $file done -# Delete empty directories +# Deletes empty directories. find . -type d -empty -delete \ No newline at end of file diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Api/Bit.Websites.Careers.Api.csproj b/src/Websites/Careers/src/Bit.Websites.Careers.Api/Bit.Websites.Careers.Api.csproj deleted file mode 100644 index 9d9d06b784..0000000000 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Api/Bit.Websites.Careers.Api.csproj +++ /dev/null @@ -1,69 +0,0 @@ - - - net8.0 - - - - - - - - - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Api/IdentityCertificate.pfx b/src/Websites/Careers/src/Bit.Websites.Careers.Api/IdentityCertificate.pfx deleted file mode 100644 index 7ad2e2842b..0000000000 Binary files a/src/Websites/Careers/src/Bit.Websites.Careers.Api/IdentityCertificate.pfx and /dev/null differ diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Api/Middlewares/HttpResponseExceptionHandlerMiddleware.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Api/Middlewares/HttpResponseExceptionHandlerMiddleware.cs deleted file mode 100644 index 7a4d085b0c..0000000000 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Api/Middlewares/HttpResponseExceptionHandlerMiddleware.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System.Net; -using System.Reflection; - -namespace Bit.Websites.Careers.Api.Middlewares; - -public class HttpResponseExceptionHandlerMiddleware -{ - private readonly RequestDelegate _next; - - public HttpResponseExceptionHandlerMiddleware(RequestDelegate next) - { - _next = next; - } - - public async Task Invoke(HttpContext context, IHostEnvironment webHostEnvironment) - { - // Using the Request-Id header, one can find the log for server-related exceptions - context.Response.Headers.Append("Request-ID", context.TraceIdentifier); - - try - { - await _next(context); - } - catch (Exception e) - { - var exception = UnWrapException(e); - var knownException = exception as KnownException; - - // The details of all of the exceptions are returned only in dev mode. in any other modes like production, only the details of the known exceptions are returned. - string key = knownException?.Key ?? nameof(UnknownException); - string message = exception.Message; - - var statusCode = (int)(exception is RestException restExp ? restExp.StatusCode : HttpStatusCode.InternalServerError); - - RestErrorInfo restExceptionPayload = new RestErrorInfo - { - Key = key, - Message = message, - ExceptionType = knownException?.GetType().FullName ?? typeof(UnknownException).FullName - }; - - if (exception is ResourceValidationException validationException) - { - restExceptionPayload.Payload = validationException.Payload; - } - - context.Response.StatusCode = statusCode; - - await context.Response.WriteAsJsonAsync(restExceptionPayload); - } - } - - private Exception UnWrapException(Exception exp) - { - return (exp is TargetInvocationException && exp.InnerException is not null) - ? exp.InnerException - : exp; - } -} diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Api/Program.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Api/Program.cs deleted file mode 100644 index babf2de54d..0000000000 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Api/Program.cs +++ /dev/null @@ -1,9 +0,0 @@ -var builder = WebApplication.CreateBuilder(args); - -Bit.Websites.Careers.Api.Startup.Services.Add(builder.Services, builder.Environment, builder.Configuration); - -var app = builder.Build(); - -Bit.Websites.Careers.Api.Startup.Middlewares.Use(app, builder.Environment, builder.Configuration); - -app.Run(); diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Api/Startup/Middlewares.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Api/Startup/Middlewares.cs deleted file mode 100644 index f1ed1c7286..0000000000 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Api/Startup/Middlewares.cs +++ /dev/null @@ -1,71 +0,0 @@ -using Microsoft.Net.Http.Headers; - -namespace Bit.Websites.Careers.Api.Startup; - -public class Middlewares -{ - public static void Use(IApplicationBuilder app, IHostEnvironment env, IConfiguration configuration) - { - app.UseForwardedHeaders(); - - if (env.IsDevelopment()) - { - app.UseDeveloperExceptionPage(); - -#if BlazorWebAssembly - if (env.IsDevelopment()) - { - app.UseWebAssemblyDebugging(); - } -#endif - } - -#if BlazorWebAssembly - app.UseBlazorFrameworkFiles(); -#endif - - if (env.IsDevelopment() is false) - { - app.UseHttpsRedirection(); - app.UseResponseCompression(); - } - - app.UseStaticFiles(new StaticFileOptions - { - OnPrepareResponse = ctx => - { - // https://bitplatform.dev/templates/cache-mechanism - ctx.Context.Response.GetTypedHeaders().CacheControl = new CacheControlHeaderValue() - { - MaxAge = TimeSpan.FromDays(7), - Public = true - }; - } - }); - - app.UseRouting(); - - app.UseCors(options => options.WithOrigins("https://localhost:4001").AllowAnyHeader().AllowAnyMethod().AllowCredentials()); - - app.UseResponseCaching(); - app.UseAuthentication(); - app.UseAuthorization(); - - app.UseSwagger(); - - app.UseSwaggerUI(options => - { - options.InjectJavascript("/swagger/swagger-utils.js"); - }); - - app.UseEndpoints(endpoints => - { - endpoints.MapControllers().RequireAuthorization(); - - -#if BlazorWebAssembly - endpoints.MapFallbackToPage("/_Host"); -#endif - }); - } -} diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Api/Startup/Services.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Api/Startup/Services.cs deleted file mode 100644 index ee1bb9339d..0000000000 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Api/Startup/Services.cs +++ /dev/null @@ -1,85 +0,0 @@ -using System.IO.Compression; -using Microsoft.AspNetCore.HttpOverrides; -using Microsoft.AspNetCore.OData; -using Microsoft.AspNetCore.ResponseCompression; -#if BlazorWebAssembly -using Microsoft.AspNetCore.Components; -using Bit.Websites.Careers.Web.Services; -#endif - -namespace Bit.Websites.Careers.Api.Startup; - -public static class Services -{ - public static void Add(IServiceCollection services, IWebHostEnvironment env, IConfiguration configuration) - { - // Services being registered here can get injected into controllers and services in Api project. - - services.AddSharedServices(); - -#if BlazorWebAssembly - services.AddTransient(); - services.AddClientSharedServices(); - - // In the Pre-Rendering mode, the configured HttpClient will use the access_token provided by the cookie in the request, so the pre-rendered content would be fitting for the current user. - services.AddHttpClient("WebAssemblyPreRenderingHttpClient") - .ConfigurePrimaryHttpMessageHandler() - .ConfigureHttpClient((sp, httpClient) => - { - NavigationManager navManager = sp.GetRequiredService().HttpContext!.RequestServices.GetRequiredService(); - httpClient.BaseAddress = new Uri($"{navManager.BaseUri}api/"); - }); - services.AddScoped(); - - services.AddScoped(sp => - { - IHttpClientFactory httpClientFactory = sp.GetRequiredService(); - return httpClientFactory.CreateClient("WebAssemblyPreRenderingHttpClient"); - // this is for pre rendering of blazor webassembly - // for other usages of httpclient, for example calling 3rd party apis, either use services.AddHttpClient("NamedHttpClient") or services.AddHttpClient(); - }); - services.AddRazorPages(); - services.AddMvcCore(); -#endif - - services.AddCors(); - - services - .AddControllers() - .AddOData(options => options.EnableQueryFeatures()) - .ConfigureApiBehaviorOptions(options => - { - options.InvalidModelStateResponseFactory = context => - { - throw new ResourceValidationException(context.ModelState.Select(ms => (ms.Key, ms.Value!.Errors.Select(e => new LocalizedString(e.ErrorMessage, e.ErrorMessage)).ToArray())).ToArray()); - }; - }); - - services.Configure(options => - { - options.ForwardedHeaders = ForwardedHeaders.All; - options.ForwardedHostHeaderName = "X-Host"; - }); - - services.AddResponseCaching(); - - services.AddHttpContextAccessor(); - - services.AddResponseCompression(opts => - { - opts.EnableForHttps = true; - opts.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(new[] { "application/octet-stream" }).ToArray(); - opts.Providers.Add(); - opts.Providers.Add(); - }) - .Configure(opt => opt.Level = CompressionLevel.Fastest) - .Configure(opt => opt.Level = CompressionLevel.Fastest); - - services.AddEndpointsApiExplorer(); - - services.AddAutoMapper(typeof(Program).Assembly); - - services.AddSwaggerGen(); - - } -} diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Api/appsettings.Development.json b/src/Websites/Careers/src/Bit.Websites.Careers.Api/appsettings.Development.json deleted file mode 100644 index 0222f850eb..0000000000 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Api/appsettings.Development.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "AppSettings": { - "WebServerAddress": "https://localhost:4001/" - } -} \ No newline at end of file diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Api/wwwroot/swagger/swagger-utils.js b/src/Websites/Careers/src/Bit.Websites.Careers.Api/wwwroot/swagger/swagger-utils.js deleted file mode 100644 index b3ba1c1691..0000000000 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Api/wwwroot/swagger/swagger-utils.js +++ /dev/null @@ -1,232 +0,0 @@ -/* -based on: https://www.codedesigntips.com/2021/06/28/swagger-ui-with-login-form-and-role-based-api-visibility/ -*/ -(() => { - window.addEventListener('load', () => setTimeout(initLoginForm, 0), false); -})(); - -const ACCESS_TOKEN_COOKIE_NAME = 'access_token'; -let accessTokenExpiresIn = 0; - -const initLoginForm = () => { - const swagger = window.ui; - if (!swagger) { - console.error('Swagger wasn\'t found'); - return; - } - - overrideSwaggerAuthorizeEvent(swagger); - overrideSwaggerLogoutEvent(swagger); - tryAuthorizeWithLocalData(swagger); - showLoginUI(swagger); -} - -const tryAuthorizeWithLocalData = (swagger) => { - if (isAuthorized(swagger)) - return; - - const token = getCookie(ACCESS_TOKEN_COOKIE_NAME); - if (!token) - return; - - const authorizationObject = getAuthorizationRequestObject(token); - swagger.authActions.authorize(authorizationObject); -} - -const overrideSwaggerAuthorizeEvent = (swagger) => { - const originalAuthorize = swagger.authActions.authorize; - swagger.authActions.authorize = async (args) => { - const result = await originalAuthorize(args); - - if (!getCookie(ACCESS_TOKEN_COOKIE_NAME)) { - setCookie(ACCESS_TOKEN_COOKIE_NAME, result.payload.bearerAuth.value, accessTokenExpiresIn); - } - - reloadPage(swagger); - return result; - }; -} - -const overrideSwaggerLogoutEvent = (swagger) => { - const originalLogout = swagger.authActions.logout; - swagger.authActions.logout = async (args) => { - const result = await originalLogout(args); - removeCookie(ACCESS_TOKEN_COOKIE_NAME); - reloadPage(swagger); - return result; - }; -} - -const showLoginUI = (swagger) => { - new MutationObserver(function (mutations, self) { - const descriptionDiv = isLoginFormMustShow(swagger); - if (descriptionDiv) - createLoginUI(swagger, descriptionDiv); - }).observe(document, {childList: true, subtree: true}); -} - -const isLoginFormMustShow = (swagger) => { - const rootDiv = document.querySelector("#swagger-ui > section > div.swagger-ui > div:nth-child(2)"); - if (rootDiv == null) - return false; - - const informationContainerDiv = rootDiv.querySelector("div.information-container.wrapper"); - if (informationContainerDiv == null) - return false; - - const descriptionDiv = informationContainerDiv.querySelector("section > div > div > div.description"); - if (descriptionDiv == null) - return false; - - const loginDiv = descriptionDiv.querySelector("div.login"); - if (loginDiv != null) - return false; - - if (isAuthorized(swagger)) - return false; - - return descriptionDiv; -} - -const createLoginUI = function (swagger, rootDiv) { - const div = document.createElement("div"); - div.className = "login"; - - rootDiv.appendChild(div); - - //UserName - const userNameLabel = document.createElement("label"); - div.appendChild(userNameLabel); - - const userNameSpan = document.createElement("span"); - userNameSpan.innerText = "User"; - userNameLabel.appendChild(userNameSpan); - - const userNameInput = document.createElement("input"); - userNameInput.type = "text"; - userNameInput.style = "margin-left: 10px; margin-right: 10px;"; - userNameLabel.appendChild(userNameInput); - - //Password - const passwordLabel = document.createElement("label"); - div.appendChild(passwordLabel); - - const passwordSpan = document.createElement("span"); - passwordSpan.innerText = "Password"; - passwordLabel.appendChild(passwordSpan); - - const passwordInput = document.createElement("input"); - passwordInput.type = "password"; - passwordInput.style = "margin-left: 10px; margin-right: 10px;"; - passwordLabel.appendChild(passwordInput); - - //Login button - const loginButton = document.createElement("button") - loginButton.type = "submit"; - loginButton.type = "button"; - loginButton.classList.add("btn"); - loginButton.classList.add("auth"); - loginButton.classList.add("authorize"); - loginButton.classList.add("button"); - loginButton.innerText = "Login"; - loginButton.onclick = function () { - const userName = userNameInput.value; - const password = passwordInput.value; - - if (userName === "" || password === "") { - alert("Insert userName and password!"); - return; - } - - login(swagger, userName, password); - }; - - div.appendChild(loginButton); -} - -const login = async (swagger, userName, password) => { - const response = await fetch('/api/Auth/SignIn', { - headers: {"Content-Type": "application/json; charset=utf-8"}, - method: 'POST', - body: JSON.stringify({"userName": userName, "password": password}) - }) - if (response.ok) { - const result = await response.json(); - const accessToken = result.accessToken; - accessTokenExpiresIn = result.expiresIn; - - const authorizationObject = getAuthorizationRequestObject(accessToken); - swagger.authActions.authorize(authorizationObject); - } else { - alert(await response.text()) - } -} - -const getAuthorizationRequestObject = (accessToken) => { - return { - "bearerAuth": { - "name": "Bearer", - "schema": { - "type": "apiKey", - "description": "JWT Authorization header using the Bearer scheme.", - "name": "Authorization", - "in": "header" - }, - value: accessToken - }, - }; -} - -const getCurrentUrl = (swagger) => { - const spec = swagger.getState()._root.entries.find(e => e[0] === 'spec'); - if (!spec) - return undefined; - - const url = spec[1]._root.entries.find(e => e[0] === 'url'); - if (!url) - return undefined; - - return url[1]; -} - -const reloadPage = (swagger) => { - const url = getCurrentUrl(swagger); - if (url) { - swagger.specActions.download(url); - } -}; - -function getAuthorization(swagger) { - return swagger.auth()._root.entries.find(e => e[0] === 'authorized'); -} - -function isAuthorized(swagger) { - const auth = getAuthorization(swagger); - return auth && auth[1].size !== 0; -} - -function setCookie(name, value, seconds) { - const date = new Date(); - date.setSeconds(date.getSeconds() + seconds); - document.cookie = `${name}=${value};expires=${date.toUTCString()};path=/`; -} - -function getCookie(name) { - const cookies = document.cookie.split(';'); - for (let i = 0; i < cookies.length; i++) { - const cookie = cookies[i].split('='); - if (trim(cookie[0]) === escape(name)) { - return unescape(trim(cookie[1])); - } - } - return null; -} - -function removeCookie(name) { - const date = new Date(); - document.cookie = `${name}=;expires=${date.toUTCString()};path=/`; -} - -function trim(value) { - return value.replace(/^\s+|\s+$/g, ''); -} \ No newline at end of file diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Bit.Websites.Careers.Web.csproj b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Bit.Websites.Careers.Client.csproj similarity index 59% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/Bit.Websites.Careers.Web.csproj rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/Bit.Websites.Careers.Client.csproj index 9a7b4a1da9..25758a3898 100644 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Bit.Websites.Careers.Web.csproj +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Bit.Websites.Careers.Client.csproj @@ -1,11 +1,12 @@ - + + net8.0 - enable enable - - true - false + enable + true + Default + true false @@ -15,11 +16,7 @@ - - - - - + @@ -32,8 +29,6 @@ - - all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -42,22 +37,17 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - - - + + + + @@ -66,9 +56,21 @@ + + + True + True + $([System.String]::Copy('%(Filename)').Replace('.Designer','')).resx + + + PublicResXFileCodeGenerator + %(Filename).Designer.cs + + + - + diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Components/CareerBox.razor b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Components/CareerBox.razor similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/Components/CareerBox.razor rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/Components/CareerBox.razor diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Components/CareerBox.razor.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Components/CareerBox.razor.cs similarity index 78% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/Components/CareerBox.razor.cs rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/Components/CareerBox.razor.cs index f04334f55f..36a6560c87 100644 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Components/CareerBox.razor.cs +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Components/CareerBox.razor.cs @@ -1,6 +1,6 @@ using Bit.Websites.Careers.Shared.Dtos.Account; -namespace Bit.Websites.Careers.Web.Components +namespace Bit.Websites.Careers.Client.Components { public partial class CareerBox { diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Components/CareerBox.razor.scss b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Components/CareerBox.razor.scss similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/Components/CareerBox.razor.scss rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/Components/CareerBox.razor.scss diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Components/IntroBox.razor b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Components/IntroBox.razor similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/Components/IntroBox.razor rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/Components/IntroBox.razor diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Components/IntroBox.razor.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Components/IntroBox.razor.cs similarity index 70% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/Components/IntroBox.razor.cs rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/Components/IntroBox.razor.cs index 5daa7408c5..c9eccefd49 100644 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Components/IntroBox.razor.cs +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Components/IntroBox.razor.cs @@ -1,4 +1,4 @@ -namespace Bit.Websites.Careers.Web.Components +namespace Bit.Websites.Careers.Client.Components { public partial class IntroBox { diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Components/IntroBox.razor.scss b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Components/IntroBox.razor.scss similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/Components/IntroBox.razor.scss rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/Components/IntroBox.razor.scss diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Client/Extensions/IConfigurationBuilderExtensions.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Extensions/IConfigurationBuilderExtensions.cs new file mode 100644 index 0000000000..8d232fca9d --- /dev/null +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Extensions/IConfigurationBuilderExtensions.cs @@ -0,0 +1,12 @@ +using System.Reflection; + +namespace Microsoft.Extensions.Configuration; + +public static class IConfigurationBuilderExtensions +{ + public static void AddClientConfigurations(this IConfigurationBuilder builder) + { + var assembly = Assembly.Load("Bit.Websites.Careers.Client"); + builder.AddJsonStream(assembly.GetManifestResourceStream("Bit.Websites.Careers.Client.appsettings.json")!); + } +} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Extensions/IConfigurationExtensions.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Extensions/IConfigurationExtensions.cs similarity index 87% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/Extensions/IConfigurationExtensions.cs rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/Extensions/IConfigurationExtensions.cs index e88b29bed5..4bb315c1db 100644 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Extensions/IConfigurationExtensions.cs +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Extensions/IConfigurationExtensions.cs @@ -1,5 +1,4 @@ -//-:cnd:noEmit -namespace Microsoft.Extensions.Configuration; +namespace Microsoft.Extensions.Configuration; public static class IConfigurationExtensions { public static string GetApiServerAddress(this IConfiguration configuration) diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Client/Extensions/IListExtensions.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Extensions/IListExtensions.cs new file mode 100644 index 0000000000..8f50eb4679 --- /dev/null +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Extensions/IListExtensions.cs @@ -0,0 +1,23 @@ +namespace System.Collections.Generic; + +public static class IListExtensions +{ + // Basically a Polyfill since we now expose IList instead of List + // which is better but IList doesn't have AddRange + public static void AddRange(this IList list, IEnumerable items) + { + ArgumentNullException.ThrowIfNull(list); + ArgumentNullException.ThrowIfNull(items); + + if (list is List asList) + { + asList.AddRange(items); + return; + } + + foreach (T item in items) + { + list.Add(item); + } + } +} diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Client/Extensions/IServiceCollectionExtensions.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Extensions/IServiceCollectionExtensions.cs new file mode 100644 index 0000000000..b62f73a582 --- /dev/null +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Extensions/IServiceCollectionExtensions.cs @@ -0,0 +1,24 @@ +using Bit.Websites.Careers.Client.Services.HttpMessageHandlers; + +namespace Microsoft.Extensions.DependencyInjection; + +public static class IServiceCollectionExtensions +{ + public static IServiceCollection AddClientSharedServices(this IServiceCollection services) + { + services.AddSharedServices(); + + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddBitBlazorUIServices(); + + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + + services.AddScoped(); + + return services; + } +} diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Client/Extensions/JsRuntimeExtension.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Extensions/JsRuntimeExtension.cs new file mode 100644 index 0000000000..ba3ef05735 --- /dev/null +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Extensions/JsRuntimeExtension.cs @@ -0,0 +1,19 @@ +namespace Microsoft.JSInterop; + +public static class JSRuntimeExtension +{ + public static async Task ToggleBodyOverflow(this IJSRuntime jsRuntime, bool isNavOpen) + { + await jsRuntime.InvokeVoidAsync("toggleBodyOverflow", isNavOpen); + } + + public static async Task GoBack(this IJSRuntime jsRuntime) + { + await jsRuntime.InvokeVoidAsync("App.goBack"); + } + + public static async Task ApplyBodyElementClasses(this IJSRuntime jsRuntime, List cssClasses, Dictionary cssVariables) + { + await jsRuntime.InvokeVoidAsync("App.applyBodyElementClasses", cssClasses, cssVariables); + } +} diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Pages/HomePage.razor b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Pages/HomePage.razor similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/Pages/HomePage.razor rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/Pages/HomePage.razor diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Pages/HomePage.razor.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Pages/HomePage.razor.cs similarity index 99% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/Pages/HomePage.razor.cs rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/Pages/HomePage.razor.cs index 419770ad77..c4d46a7be1 100644 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Pages/HomePage.razor.cs +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Pages/HomePage.razor.cs @@ -1,6 +1,6 @@ using Bit.Websites.Careers.Shared.Dtos.Account; -namespace Bit.Websites.Careers.Web.Pages +namespace Bit.Websites.Careers.Client.Pages { public partial class HomePage { diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Pages/HomePage.razor.scss b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Pages/HomePage.razor.scss similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/Pages/HomePage.razor.scss rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/Pages/HomePage.razor.scss diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Client/Program.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Program.cs new file mode 100644 index 0000000000..dd6cdd4b8b --- /dev/null +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Program.cs @@ -0,0 +1,22 @@ +using Bit.Websites.Careers.Client.Services.HttpMessageHandlers; +using Microsoft.AspNetCore.Components.WebAssembly.Hosting; + +var builder = WebAssemblyHostBuilder.CreateDefault(args); + +builder.Configuration.AddClientConfigurations(); + +Uri.TryCreate(builder.Configuration.GetApiServerAddress(), UriKind.RelativeOrAbsolute, out var apiServerAddress); + +if (apiServerAddress!.IsAbsoluteUri is false) +{ + apiServerAddress = new Uri($"{builder.HostEnvironment.BaseAddress}{apiServerAddress}"); +} + +builder.Services.AddSingleton(sp => new HttpClient(sp.GetRequiredService()) { BaseAddress = apiServerAddress }); +builder.Services.AddScoped(); + +builder.Services.AddClientSharedServices(); + +var host = builder.Build(); + +await host.RunAsync(); diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/App.razor b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Routes.razor similarity index 74% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/App.razor rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/Routes.razor index 6a216a752e..181706f466 100644 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Web/App.razor +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Routes.razor @@ -1,12 +1,12 @@  bit platform software development as a service - + - bit foundation - + diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Client/Routes.razor.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Routes.razor.cs new file mode 100644 index 0000000000..78578a2fb8 --- /dev/null +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Routes.razor.cs @@ -0,0 +1,21 @@ +using Microsoft.AspNetCore.Components.Routing; + +namespace Bit.Websites.Careers.Client; + +public partial class Routes +{ + private List _lazyLoadedAssemblies = []; + [AutoInject] private Microsoft.AspNetCore.Components.WebAssembly.Services.LazyAssemblyLoader _assemblyLoader = default!; + + private async Task OnNavigateAsync(NavigationContext args) + { + if (OperatingSystem.IsBrowser()) + { + if ((args.Path is "dashboard") && _lazyLoadedAssemblies.Any(asm => asm.GetName().Name == "Newtonsoft.Json") is false) + { + var assemblies = await _assemblyLoader.LoadAssembliesAsync(["Newtonsoft.Json.wasm", "System.Private.Xml.wasm", "System.Data.Common.wasm"]); + _lazyLoadedAssemblies.AddRange(assemblies); + } + } + } +} diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Client/Scripts/app.ts b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Scripts/app.ts new file mode 100644 index 0000000000..598ec03123 --- /dev/null +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Scripts/app.ts @@ -0,0 +1,41 @@ +//declare var hljs: any; + +function toggleBodyOverflow(isMenuOpen: boolean) { + if (window.innerWidth <= 900) { + if (isMenuOpen) { + document.body.style.overflow = "hidden"; + } else { + document.body.style.overflow = "auto"; + } + } +} + +function RegisterOnScrollToChangeGettingStartedSideRailStyle(element: any) { + window.addEventListener('scroll', (event) => { + if (document.documentElement.scrollTop >= 500) { + element.classList.add("fixed-getting-started-side-rail-section"); + } + else { + element.classList.remove("fixed-getting-started-side-rail-section"); + } + }); +} + +function goToTop() { + window.scrollTo({ top: 0 }); +} + +declare class BitTheme { static init(options: any): void; }; + +BitTheme.init({ + system: true, + onChange: (newTheme: string, oldThem: string) => { + if (newTheme === 'dark') { + document.body.classList.add('bit-theme-dark'); + document.body.classList.remove('bit-theme-light'); + } else { + document.body.classList.add('bit-theme-light'); + document.body.classList.remove('bit-theme-dark'); + } + } +}); \ No newline at end of file diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Services/Contracts/IExceptionHandler.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Services/Contracts/IExceptionHandler.cs similarity index 67% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/Services/Contracts/IExceptionHandler.cs rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/Services/Contracts/IExceptionHandler.cs index bb5b5483b4..a2d1fbeb89 100644 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Services/Contracts/IExceptionHandler.cs +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Services/Contracts/IExceptionHandler.cs @@ -1,4 +1,4 @@ -namespace Bit.Websites.Careers.Web.Services.Contracts; +namespace Bit.Websites.Careers.Client.Services.Contracts; public interface IExceptionHandler { diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Client/Services/Contracts/IPrerenderStateService.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Services/Contracts/IPrerenderStateService.cs new file mode 100644 index 0000000000..0c043dd3bb --- /dev/null +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Services/Contracts/IPrerenderStateService.cs @@ -0,0 +1,17 @@ +namespace Bit.Websites.Careers.Client.Services.Contracts; + +/// +/// This service simplifies the process of persisting application state in Pre-Rendering mode +/// (explained in this documentation: https://docs.microsoft.com/en-us/aspnet/core/blazor/components/prerendering-and-integration#persist-prerendered-state). +/// If your project does not require prerendering to be enabled, you can completely remove this service and its usages from your project. +/// +public interface IPrerenderStateService +{ + /// + /// Instead of using ApplicationState.TryTakeFromJson, ApplicationState.RegisterOnPersisting, + /// and ApplicationState.PersistAsJson (explained here: https://docs.microsoft.com/en-us/aspnet/core/blazor/components/prerendering-and-integration#persist-prerendered-state), + /// one can easily use the following method () in the OnInit lifecycle method of the Blazor components or pages + /// to retrieve everything that requires an async-await (like current user's info). + /// + Task GetValue(string key, Func> factory); +} diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Client/Services/Contracts/IPubSubService.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Services/Contracts/IPubSubService.cs new file mode 100644 index 0000000000..af0d7589be --- /dev/null +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Services/Contracts/IPubSubService.cs @@ -0,0 +1,10 @@ +namespace Bit.Websites.Careers.Client.Services.Contracts; + +/// +/// Contract for Publish/Subscribe pattern. +/// +public interface IPubSubService +{ + void Publish(string message, object? payload); + Action Subscribe(string message, Action handler); +} diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Client/Services/ExceptionHandler.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Services/ExceptionHandler.cs new file mode 100644 index 0000000000..9375ad3f50 --- /dev/null +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Services/ExceptionHandler.cs @@ -0,0 +1,27 @@ +using System.Diagnostics; + +namespace Bit.Websites.Careers.Client.Services; + +public partial class ExceptionHandler : IExceptionHandler +{ + [AutoInject] MessageBoxService _messageBoxService = default!; + + public void Handle(Exception exception, IDictionary? parameters = null) + { +#if DEBUG + string exceptionMessage = (exception as KnownException)?.Message ?? exception.ToString(); + _ = _messageBoxService.Show(exceptionMessage, "Error"); + _ = Console.Out.WriteLineAsync(exceptionMessage); + Debugger.Break(); +#else + if (exception is KnownException knownException) + { + _ = _messageBoxService.Show(knownException.Message, "Error"); + } + else + { + _ = _messageBoxService.Show("Unknown error", "Error"); + } +#endif + } +} diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Client/Services/HttpMessageHandlers/ExceptionDelegatingHandler.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Services/HttpMessageHandlers/ExceptionDelegatingHandler.cs new file mode 100644 index 0000000000..a80a67b5e3 --- /dev/null +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Services/HttpMessageHandlers/ExceptionDelegatingHandler.cs @@ -0,0 +1,60 @@ +using System.Net; + +namespace Bit.Websites.Careers.Client.Services.HttpMessageHandlers; + +public class ExceptionDelegatingHandler + : DelegatingHandler +{ + public ExceptionDelegatingHandler(HttpClientHandler httpClientHandler) + : base(httpClientHandler) + { + + } + + public ExceptionDelegatingHandler() + { + + } + + protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + { + bool serverCommunicationSuccess = false; + + try + { + var response = await base.SendAsync(request, cancellationToken); + + serverCommunicationSuccess = true; + + if (response.IsSuccessStatusCode is false && response.Content.Headers.ContentType?.MediaType?.Contains("application/json", StringComparison.InvariantCultureIgnoreCase) is true) + { + if (response.Headers.TryGetValues("Request-ID", out IEnumerable? values) && values is not null && values.Any()) + { + RestErrorInfo restError = (await response!.Content.ReadFromJsonAsync(AppJsonContext.Default.RestErrorInfo, cancellationToken))!; + + Type exceptionType = typeof(RestErrorInfo).Assembly.GetType(restError.ExceptionType!) ?? typeof(UnknownException); + + var args = new List { restError.Message! }; + + if (exceptionType == typeof(ResourceValidationException)) + { + args.Add(restError.Payload); + } + + Exception exp = (Exception)Activator.CreateInstance(exceptionType, args.ToArray())!; + + throw exp; + } + } + + response.EnsureSuccessStatusCode(); + + return response; + } + catch (Exception exp) when ((exp is HttpRequestException && serverCommunicationSuccess is false) + || exp is TaskCanceledException tcExp && tcExp.InnerException is TimeoutException) + { + throw new ServerConnectionException(nameof(ServerConnectionException), exp); + } + } +} diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Client/Services/HttpMessageHandlers/RetryDelegatingHandler.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Services/HttpMessageHandlers/RetryDelegatingHandler.cs new file mode 100644 index 0000000000..fdb07de210 --- /dev/null +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Services/HttpMessageHandlers/RetryDelegatingHandler.cs @@ -0,0 +1,55 @@ +namespace Bit.Websites.Careers.Client.Services.HttpMessageHandlers; + +public class RetryDelegatingHandler + : DelegatingHandler +{ + public RetryDelegatingHandler(ExceptionDelegatingHandler handler) + : base(handler) + { + + } + + public RetryDelegatingHandler() + { + + } + + protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + { + var delays = GetDelays(scaleFirstTry: TimeSpan.FromSeconds(3), maxRetries: 3).ToArray(); + + Exception? lastExp = null; + + foreach (var delay in delays) + { + try + { + return await base.SendAsync(request, cancellationToken); + } + catch (Exception exp) when (exp is not KnownException) + { + lastExp = exp; + await Task.Delay(delay, cancellationToken); + } + } + + throw lastExp!; + } + + private static IEnumerable GetDelays(TimeSpan scaleFirstTry, int maxRetries) + { + TimeSpan maxValue = TimeSpan.MaxValue; + var maxTimeSpanDouble = maxValue.Ticks - 1_000.0; + var i = 0; + var targetTicksFirstDelay = scaleFirstTry.Ticks; + var num = 0.0; + for (; i < maxRetries; i++) + { + var num2 = i + Random.Shared.NextDouble(); + var next = Math.Pow(2.0, num2) * Math.Tanh(Math.Sqrt(4.0 * num2)); + var num3 = next - num; + yield return TimeSpan.FromTicks((long)Math.Min(num3 * 0.7_142_857_142_857_143 * targetTicksFirstDelay, maxTimeSpanDouble)); + num = next; + } + } +} diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Client/Services/MessageBoxService.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Services/MessageBoxService.cs new file mode 100644 index 0000000000..f5b2ad3ba0 --- /dev/null +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Services/MessageBoxService.cs @@ -0,0 +1,12 @@ +namespace Bit.Websites.Careers.Client.Services; +public partial class MessageBoxService +{ + [AutoInject] IPubSubService _pubSubService = default!; + + public async Task Show(string message, string title = "") + { + TaskCompletionSource tsc = new(); + _pubSubService.Publish(PubSubMessages.SHOW_MESSAGE, (message, title, tsc)); + await tsc.Task; + } +} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Services/StateService.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Services/PrerenderStateService.cs similarity index 75% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/Services/StateService.cs rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/Services/PrerenderStateService.cs index aa58437958..05076d9fce 100644 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Services/StateService.cs +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Services/PrerenderStateService.cs @@ -1,21 +1,24 @@  -namespace Bit.Websites.Sales.Web.Services; +using Microsoft.AspNetCore.Components.Web; + +namespace Bit.Websites.Careers.Client.Services; // Using this class, persisting the application state on Pre-Rendering mode (explained here: https://docs.microsoft.com/en-us/aspnet/core/blazor/components/prerendering-and-integration#persist-prerendered-state) will be very simple in this multi-mode Template project. -#if (BlazorWebAssembly || BlazorServer) && SSR -public class StateService : IStateService, IAsyncDisposable +public class PrerenderStateService : IPrerenderStateService, IAsyncDisposable { private PersistingComponentStateSubscription? _subscription; private readonly PersistentComponentState _applicationState; - private readonly ConcurrentDictionary _values = new ConcurrentDictionary(); + private readonly ConcurrentDictionary _values = new(); - public StateService(PersistentComponentState applicationState) + public PrerenderStateService(PersistentComponentState applicationState) { _applicationState = applicationState; if (OperatingSystem.IsBrowser() is false) - _subscription = applicationState.RegisterOnPersisting(PersistAsJson); + { + _subscription = applicationState.RegisterOnPersisting(PersistAsJson, RenderModeProvider.Current); + } } public async Task GetValue(string key, Func> factory) @@ -48,12 +51,3 @@ public async ValueTask DisposeAsync() _subscription?.Dispose(); } } -#else -public class StateService : IStateService -{ - public Task GetValue(string key, Func> factory) - { - return factory(); - } -} -#endif diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Client/Services/PubSubMessages.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Services/PubSubMessages.cs new file mode 100644 index 0000000000..fbeb46d12a --- /dev/null +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Services/PubSubMessages.cs @@ -0,0 +1,6 @@ +namespace Bit.Websites.Careers.Client.Services; + +public static class PubSubMessages +{ + public const string SHOW_MESSAGE = "SHOWMESSAGE"; +} diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Services/PubSubService.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Services/PubSubService.cs similarity index 60% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/Services/PubSubService.cs rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/Services/PubSubService.cs index 863f9ecfa5..40066461c6 100644 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Services/PubSubService.cs +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Services/PubSubService.cs @@ -1,10 +1,13 @@ -namespace Bit.Websites.Careers.Web.Services; +namespace Bit.Websites.Careers.Client.Services; +/// +/// For more information docs. +/// public class PubSubService : IPubSubService { private readonly ConcurrentDictionary>> _handlers = new(); - public void Pub(string message, object? payload) + public void Publish(string message, object? payload) { if (_handlers.TryGetValue(message, out var handlers)) { @@ -12,11 +15,11 @@ public void Pub(string message, object? payload) } } - public Action Sub(string message, Action handler) + public Action Subscribe(string message, Action handler) { var handlers = _handlers.ContainsKey(message) ? _handlers[message] - : _handlers[message] = new List>(); + : _handlers[message] = []; handlers.Add(handler); diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Client/Services/RenderModeProvider.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Services/RenderModeProvider.cs new file mode 100644 index 0000000000..399e184c35 --- /dev/null +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Services/RenderModeProvider.cs @@ -0,0 +1,18 @@ +using Microsoft.AspNetCore.Components.Web; + +namespace Bit.Websites.Careers.Client.Services; + +public static class RenderModeProvider +{ + static IComponentRenderMode PrerenderEnabledAuto = RenderMode.InteractiveAuto; + static IComponentRenderMode PrerenderEnabledBlazorWasm = RenderMode.InteractiveWebAssembly; + static IComponentRenderMode PrerenderEnabledBlazorServer = RenderMode.InteractiveServer; + + static IComponentRenderMode Auto = new InteractiveAutoRenderMode(prerender: false); + static IComponentRenderMode BlazorWasm = new InteractiveWebAssemblyRenderMode(prerender: false); + static IComponentRenderMode BlazorServer = new InteractiveServerRenderMode(prerender: false); + + // PrerenderOnly: In order to have prerender only mode, simply remove @rendermode usages from App.razor + + public static IComponentRenderMode Current => PrerenderEnabledAuto; +} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Components/AppComponentBase.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Shared/AppComponentBase.cs similarity index 81% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/Components/AppComponentBase.cs rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/Shared/AppComponentBase.cs index bafcaf1a26..1b9e91f4a9 100644 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Components/AppComponentBase.cs +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Shared/AppComponentBase.cs @@ -1,24 +1,28 @@ -namespace Bit.Websites.Sales.Web.Components; +namespace Bit.Websites.Careers.Client.Shared; public partial class AppComponentBase : ComponentBase { + [AutoInject] protected IJSRuntime JSRuntime = default!; + [AutoInject] protected HttpClient HttpClient = default!; - [AutoInject] protected IStateService StateService = default!; + /// + /// + /// + [AutoInject] protected IPrerenderStateService PrerenderStateService = default!; + /// + /// + /// [AutoInject] protected IPubSubService PubSubService = default!; [AutoInject] protected IConfiguration Configuration = default!; - [AutoInject] protected IJSRuntime JSRuntime { get; set; } = default!; - [AutoInject] protected NavigationManager NavigationManager = default!; - - [AutoInject] protected IStringLocalizer Localizer = default!; - + [AutoInject] protected IExceptionHandler ExceptionHandler { get; set; } = default!; - - protected async sealed override Task OnInitializedAsync() + + protected sealed override async Task OnInitializedAsync() { try { @@ -31,7 +35,7 @@ protected async sealed override Task OnInitializedAsync() } } - protected async sealed override Task OnParametersSetAsync() + protected sealed override async Task OnParametersSetAsync() { try { @@ -44,16 +48,16 @@ protected async sealed override Task OnParametersSetAsync() } } - protected async override Task OnAfterRenderAsync(bool firstRender) + /// + /// Replacement for which catches all possible exceptions in order to prevent app crash. + /// + protected virtual Task OnInitAsync() { - var currentUrl = NavigationManager.Uri.Replace(NavigationManager.BaseUri, "/", StringComparison.Ordinal); - var hashIndex = currentUrl.LastIndexOf('#'); - if (hashIndex > 0) - { - var elementId = currentUrl.Substring(hashIndex + 1); - _ = JSRuntime.InvokeVoidAsync("App.scrollIntoView", elementId); - } + return Task.CompletedTask; + } + protected override async Task OnAfterRenderAsync(bool firstRender) + { if (firstRender) { try @@ -69,12 +73,9 @@ protected async override Task OnAfterRenderAsync(bool firstRender) await base.OnAfterRenderAsync(firstRender); } - /// - /// Replacement for which catches all possible exceptions in order to prevent app crash. - /// - protected virtual Task OnInitAsync() + protected sealed override void OnInitialized() { - return Task.CompletedTask; + base.OnInitialized(); } /// diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Shared/AppErrorBoundary.razor b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Shared/AppErrorBoundary.razor similarity index 96% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/Shared/AppErrorBoundary.razor rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/Shared/AppErrorBoundary.razor index 4cb5fa222e..c198a23a93 100644 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Shared/AppErrorBoundary.razor +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Shared/AppErrorBoundary.razor @@ -14,7 +14,7 @@ else if (ErrorContent is null)

Oops, something went wrong...

- @if (ShowException) + @if (_showException) {
@CurrentException?.ToString()
} @@ -27,4 +27,4 @@ else if (ErrorContent is null) else { @ErrorContent(CurrentException) -} +} \ No newline at end of file diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Shared/AppErrorBoundary.razor.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Shared/AppErrorBoundary.razor.cs similarity index 56% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/Shared/AppErrorBoundary.razor.cs rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/Shared/AppErrorBoundary.razor.cs index adfe34385f..e2bc207aef 100644 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Shared/AppErrorBoundary.razor.cs +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Shared/AppErrorBoundary.razor.cs @@ -1,30 +1,32 @@ -namespace Bit.Websites.Careers.Web.Shared; + +namespace Bit.Websites.Careers.Client.Shared; +/// +/// https://learn.microsoft.com/en-us/aspnet/core/blazor/fundamentals/handle-errors +/// public partial class AppErrorBoundary { + private bool _showException; + [AutoInject] private IExceptionHandler _exceptionHandler = default!; [AutoInject] private NavigationManager _navigationManager = default!; - private bool ShowException { get; set; } - #if DEBUG protected override void OnInitialized() { - ShowException = true; + _showException = true; } #endif - protected override Task OnErrorAsync(Exception exception) + protected override async Task OnErrorAsync(Exception exception) { _exceptionHandler.Handle(exception); - - return Task.CompletedTask; } private void Refresh() { - _navigationManager.NavigateTo(_navigationManager.Uri, true); + _navigationManager.Refresh(forceReload: true); } private void GoHome() diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Shared/AppErrorBoundary.razor.scss b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Shared/AppErrorBoundary.razor.scss similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/Shared/AppErrorBoundary.razor.scss rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/Shared/AppErrorBoundary.razor.scss diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Shared/ChangeResponseStatusCode.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Shared/ChangePrerenderResponseStatusCode.cs similarity index 73% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/Shared/ChangeResponseStatusCode.cs rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/Shared/ChangePrerenderResponseStatusCode.cs index 2f673aef73..4ad06e9bda 100644 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Shared/ChangeResponseStatusCode.cs +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Shared/ChangePrerenderResponseStatusCode.cs @@ -1,8 +1,11 @@ using System.Net; -namespace Bit.Websites.Sales.Web.Shared; +namespace Bit.Websites.Careers.Client.Shared; -public partial class ChangeResponseStatusCode : AppComponentBase +/// +/// This component is used during prerendering to determine the value of the StatusCode parameter for the returned HTTP response. +/// +public partial class ChangePrerenderResponseStatusCode : AppComponentBase { [Parameter] public HttpStatusCode StatusCode { get; set; } @@ -14,7 +17,7 @@ public partial class ChangeResponseStatusCode : AppComponentBase protected override Task OnInitAsync() { - if (_httpContextAccessorType is not null && BlazorModeDetector.Current.IsBlazorWebAssembly()) + if (_httpContextAccessorType is not null) { var httpContextAccessor = _serviceProvider.GetService(_httpContextAccessorType); diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Shared/Footer.razor b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Shared/Footer.razor similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/Shared/Footer.razor rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/Shared/Footer.razor diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Shared/Footer.razor.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Shared/Footer.razor.cs similarity index 73% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/Shared/Footer.razor.cs rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/Shared/Footer.razor.cs index f934b6d1b8..22bbac9f8a 100644 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Shared/Footer.razor.cs +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Shared/Footer.razor.cs @@ -1,4 +1,4 @@ -namespace Bit.Websites.Careers.Web.Shared; +namespace Bit.Websites.Careers.Client.Shared; public partial class Footer { diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Shared/Footer.razor.scss b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Shared/Footer.razor.scss similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/Shared/Footer.razor.scss rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/Shared/Footer.razor.scss diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Shared/Header.razor b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Shared/Header.razor similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/Shared/Header.razor rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/Shared/Header.razor diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Shared/Header.razor.scss b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Shared/Header.razor.scss similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/Shared/Header.razor.scss rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/Shared/Header.razor.scss diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Shared/LoadingComponent.razor b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Shared/LoadingComponent.razor similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/Shared/LoadingComponent.razor rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/Shared/LoadingComponent.razor diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Shared/LoadingComponent.razor.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Shared/LoadingComponent.razor.cs similarity index 68% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/Shared/LoadingComponent.razor.cs rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/Shared/LoadingComponent.razor.cs index 38ec069ba7..e4149021c5 100644 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Shared/LoadingComponent.razor.cs +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Shared/LoadingComponent.razor.cs @@ -1,4 +1,4 @@ -namespace Bit.Websites.Sales.Web.Shared; +namespace Bit.Websites.Careers.Client.Shared; public partial class LoadingComponent { diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Shared/LoadingComponent.razor.scss b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Shared/LoadingComponent.razor.scss similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/Shared/LoadingComponent.razor.scss rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/Shared/LoadingComponent.razor.scss diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Shared/MainLayout.razor b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Shared/MainLayout.razor similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/Shared/MainLayout.razor rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/Shared/MainLayout.razor diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Client/Shared/MainLayout.razor.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Shared/MainLayout.razor.cs new file mode 100644 index 0000000000..9eb269578e --- /dev/null +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Shared/MainLayout.razor.cs @@ -0,0 +1,6 @@ +namespace Bit.Websites.Careers.Client.Shared; + +public partial class MainLayout +{ + +} diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Shared/MainLayout.razor.scss b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Shared/MainLayout.razor.scss similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/Shared/MainLayout.razor.scss rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/Shared/MainLayout.razor.scss diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Shared/MessageBox.razor b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Shared/MessageBox.razor similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/Shared/MessageBox.razor rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/Shared/MessageBox.razor diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Client/Shared/MessageBox.razor.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Shared/MessageBox.razor.cs new file mode 100644 index 0000000000..a3cb51be6d --- /dev/null +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Shared/MessageBox.razor.cs @@ -0,0 +1,73 @@ +namespace Bit.Websites.Careers.Client.Shared; + +public partial class MessageBox : IDisposable +{ + private bool _isOpen; + private string? _title; + private string? _body; + + private TaskCompletionSource? _tsc; + + private async Task OnCloseClick() + { + _isOpen = false; + await JSRuntime.ToggleBodyOverflow(false); + _tsc?.SetResult(null); + _tsc = null; + } + + private async Task OnOkClick() + { + _isOpen = false; + await JSRuntime.ToggleBodyOverflow(false); + _tsc?.SetResult(null); + _tsc = null; + } + + Action? _dispose; + bool _disposed = false; + + protected override Task OnInitAsync() + { + _dispose = PubSubService.Subscribe(PubSubMessages.SHOW_MESSAGE, async args => + { + (var message, string title, TaskCompletionSource tsc) = ((string message, string title, TaskCompletionSource tsc))args!; + await (_tsc?.Task ?? Task.CompletedTask); + _tsc = tsc; + await ShowMessageBox(message, title); + }); + + return base.OnInitAsync(); + } + + private async Task ShowMessageBox(string message, string title = "") + { + await InvokeAsync(() => + { + _ = JSRuntime.ToggleBodyOverflow(true); + + _isOpen = true; + _title = title; + _body = message; + + StateHasChanged(); + }); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (_disposed || disposing is false) return; + + _tsc?.TrySetResult(null); + _tsc = null; + _dispose?.Invoke(); + + _disposed = true; + } +} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Shared/MessageBox.razor.scss b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Shared/MessageBox.razor.scss similarity index 84% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/Shared/MessageBox.razor.scss rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/Shared/MessageBox.razor.scss index 6f73a0fc27..bbf208cc52 100644 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Shared/MessageBox.razor.scss +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Shared/MessageBox.razor.scss @@ -1,10 +1,11 @@ @import '../Styles/abstracts/_functions.scss'; +@import '../Styles/abstracts/_media-queries.scss'; .main { flex-grow: 1; display: flex; - flex-direction: column; padding: rem2(10px); + flex-direction: column; } .header { @@ -16,12 +17,12 @@ } .body { - display: flex; flex-grow: 1; - margin: rem2(10px) 0; - white-space: pre; + display: flex; overflow: auto; - max-width: rem2(960px); + max-width: 90vw; + white-space: pre; + margin: rem2(10px) 0; } .footer { diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Shared/PageNotFound.razor b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Shared/PageNotFound.razor similarity index 62% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/Shared/PageNotFound.razor rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/Shared/PageNotFound.razor index 07963193f0..5a5b7eec4b 100644 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Shared/PageNotFound.razor +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Shared/PageNotFound.razor @@ -1,6 +1,6 @@ @inherits AppComponentBase - +

404

diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Shared/PageNotFound.razor.scss b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Shared/PageNotFound.razor.scss similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/Shared/PageNotFound.razor.scss rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/Shared/PageNotFound.razor.scss diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Styles/abstracts/_colors.scss b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Styles/abstracts/_colors.scss similarity index 93% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/Styles/abstracts/_colors.scss rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/Styles/abstracts/_colors.scss index 38d3c8e200..be6333914c 100644 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Styles/abstracts/_colors.scss +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Styles/abstracts/_colors.scss @@ -19,8 +19,7 @@ $Gray6: #FCFCFC; /*--------------------*/ -$Primary: #0065EF -; +$Primary: #0065EF; $PureWhite: #ffffff; $PureBlack: #000000; @@ -38,4 +37,4 @@ $Blue5: #5CA1FF; $Red: #F56565; -$Orange1: #FFDA2F; \ No newline at end of file +$Orange1: #FFDA2F; diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Styles/abstracts/_functions.scss b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Styles/abstracts/_functions.scss similarity index 99% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/Styles/abstracts/_functions.scss rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/Styles/abstracts/_functions.scss index c2359935dd..29bd35e9c0 100644 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Styles/abstracts/_functions.scss +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Styles/abstracts/_functions.scss @@ -12,4 +12,4 @@ $html-font-size: 16px; @function rem2($pxValue) { @return #{calc(stripUnit($pxValue) / stripUnit($html-font-size))}rem; -} \ No newline at end of file +} diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Styles/abstracts/_media-queries.scss b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Styles/abstracts/_media-queries.scss similarity index 99% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/Styles/abstracts/_media-queries.scss rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/Styles/abstracts/_media-queries.scss index e5074723d1..9662a3bb91 100644 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Styles/abstracts/_media-queries.scss +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Styles/abstracts/_media-queries.scss @@ -75,4 +75,4 @@ $screen-sm-max: rem2(360px); @media screen and (min-width: #{$screen-xl-min}) { @content; } -} \ No newline at end of file +} diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Client/Styles/abstracts/_mixins.scss b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Styles/abstracts/_mixins.scss new file mode 100644 index 0000000000..e02abfc9b0 --- /dev/null +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Styles/abstracts/_mixins.scss @@ -0,0 +1 @@ + diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Client/Styles/app.scss b/src/Websites/Careers/src/Bit.Websites.Careers.Client/Styles/app.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Client/_Imports.razor b/src/Websites/Careers/src/Bit.Websites.Careers.Client/_Imports.razor new file mode 100644 index 0000000000..b7d69cef84 --- /dev/null +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Client/_Imports.razor @@ -0,0 +1,15 @@ +@using System.Reflection +@using Microsoft.JSInterop +@using Microsoft.Extensions.Logging +@using Microsoft.AspNetCore.Components +@using Microsoft.Extensions.Configuration +@using Microsoft.AspNetCore.Components.Web +@using Microsoft.AspNetCore.Components.Forms +@using Microsoft.AspNetCore.Components.Routing +@using Microsoft.AspNetCore.Components.Web.Virtualization +@using Bit.BlazorUI +@using Bit.Websites.Careers.Client +@using Bit.Websites.Careers.Client.Shared +@using Bit.Websites.Careers.Client.Pages +@using Bit.Websites.Careers.Client.Services.Contracts +@using Bit.Websites.Careers.Client.Services \ No newline at end of file diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/appsettings.json b/src/Websites/Careers/src/Bit.Websites.Careers.Client/appsettings.json similarity index 63% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/appsettings.json rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/appsettings.json index 9688f41d93..423ad00545 100644 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Web/appsettings.json +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Client/appsettings.json @@ -7,9 +7,6 @@ "Microsoft.Hosting.Lifetime": "Information" } }, - "GoogleTagManager": { - "Id": "" - }, "AllowedHosts": "*", - "ApiServerAddress": "https://localhost:5021/api/" + "ApiServerAddress": "api/" // You can also use absolute urls such as http://192.168.1.150:5000/api/ or https://todob.bitplatform.dev/api/ } diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/compilerconfig.json b/src/Websites/Careers/src/Bit.Websites.Careers.Client/compilerconfig.json similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/compilerconfig.json rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/compilerconfig.json diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/tsconfig.json b/src/Websites/Careers/src/Bit.Websites.Careers.Client/tsconfig.json similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/tsconfig.json rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/tsconfig.json diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/favicon.ico b/src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/favicon.ico similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/favicon.ico rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/favicon.ico diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/fonts/Estedad-Black.woff2 b/src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/fonts/Estedad-Black.woff2 similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/fonts/Estedad-Black.woff2 rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/fonts/Estedad-Black.woff2 diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/fonts/Estedad-Bold.woff2 b/src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/fonts/Estedad-Bold.woff2 similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/fonts/Estedad-Bold.woff2 rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/fonts/Estedad-Bold.woff2 diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/fonts/Estedad-ExtraBold.woff2 b/src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/fonts/Estedad-ExtraBold.woff2 similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/fonts/Estedad-ExtraBold.woff2 rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/fonts/Estedad-ExtraBold.woff2 diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/fonts/Estedad-ExtraLight.woff2 b/src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/fonts/Estedad-ExtraLight.woff2 similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/fonts/Estedad-ExtraLight.woff2 rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/fonts/Estedad-ExtraLight.woff2 diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/fonts/Estedad-Light.woff2 b/src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/fonts/Estedad-Light.woff2 similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/fonts/Estedad-Light.woff2 rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/fonts/Estedad-Light.woff2 diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/fonts/Estedad-Medium.woff2 b/src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/fonts/Estedad-Medium.woff2 similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/fonts/Estedad-Medium.woff2 rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/fonts/Estedad-Medium.woff2 diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/fonts/Estedad-Regular.woff2 b/src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/fonts/Estedad-Regular.woff2 similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/fonts/Estedad-Regular.woff2 rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/fonts/Estedad-Regular.woff2 diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/fonts/Estedad-SemiBold.woff2 b/src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/fonts/Estedad-SemiBold.woff2 similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/fonts/Estedad-SemiBold.woff2 rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/fonts/Estedad-SemiBold.woff2 diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/fonts/Estedad-Thin.woff2 b/src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/fonts/Estedad-Thin.woff2 similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/fonts/Estedad-Thin.woff2 rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/fonts/Estedad-Thin.woff2 diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/bit-logo.svg b/src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/bit-logo.svg similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/bit-logo.svg rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/bit-logo.svg diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/footer/github-icon-blue.svg b/src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/footer/github-icon-blue.svg similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/footer/github-icon-blue.svg rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/footer/github-icon-blue.svg diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/footer/go-to-top-icon.svg b/src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/footer/go-to-top-icon.svg similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/footer/go-to-top-icon.svg rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/footer/go-to-top-icon.svg diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/footer/linkedin-icon-blue.svg b/src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/footer/linkedin-icon-blue.svg similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/footer/linkedin-icon-blue.svg rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/footer/linkedin-icon-blue.svg diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/footer/mail-icon-blue.svg b/src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/footer/mail-icon-blue.svg similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/footer/mail-icon-blue.svg rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/footer/mail-icon-blue.svg diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/footer/whats-app-icon-blue.svg b/src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/footer/whats-app-icon-blue.svg similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/footer/whats-app-icon-blue.svg rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/footer/whats-app-icon-blue.svg diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/icons/bit-icon-512.png b/src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/icons/bit-icon-512.png similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/icons/bit-icon-512.png rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/icons/bit-icon-512.png diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/main-page/calendar-icon.svg b/src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/main-page/calendar-icon.svg similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/main-page/calendar-icon.svg rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/main-page/calendar-icon.svg diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/main-page/collaboration-avatar.svg b/src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/main-page/collaboration-avatar.svg similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/main-page/collaboration-avatar.svg rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/main-page/collaboration-avatar.svg diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/main-page/interview-avatar.svg b/src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/main-page/interview-avatar.svg similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/main-page/interview-avatar.svg rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/main-page/interview-avatar.svg diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/main-page/left-arrow-blue.svg b/src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/main-page/left-arrow-blue.svg similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/main-page/left-arrow-blue.svg rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/main-page/left-arrow-blue.svg diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/main-page/meeting-icon.svg b/src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/main-page/meeting-icon.svg similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/main-page/meeting-icon.svg rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/main-page/meeting-icon.svg diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/main-page/product-manager-img.svg b/src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/main-page/product-manager-img.svg similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/main-page/product-manager-img.svg rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/main-page/product-manager-img.svg diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/main-page/quote-down-icon.svg b/src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/main-page/quote-down-icon.svg similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/main-page/quote-down-icon.svg rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/main-page/quote-down-icon.svg diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/main-page/quote-up-icon.svg b/src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/main-page/quote-up-icon.svg similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/main-page/quote-up-icon.svg rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/main-page/quote-up-icon.svg diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/main-page/resume-avatar.svg b/src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/main-page/resume-avatar.svg similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/main-page/resume-avatar.svg rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/main-page/resume-avatar.svg diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/main-page/sample-author-avatar.svg b/src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/main-page/sample-author-avatar.svg similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/main-page/sample-author-avatar.svg rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/main-page/sample-author-avatar.svg diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/main-page/sample-img.png b/src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/main-page/sample-img.png similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/main-page/sample-img.png rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/main-page/sample-img.png diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/main-page/slides-left-arrow-empty.svg b/src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/main-page/slides-left-arrow-empty.svg similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/main-page/slides-left-arrow-empty.svg rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/main-page/slides-left-arrow-empty.svg diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/main-page/slides-right-arrow-filled.svg b/src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/main-page/slides-right-arrow-filled.svg similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/main-page/slides-right-arrow-filled.svg rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/main-page/slides-right-arrow-filled.svg diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/main-page/team-members-avatars.webp b/src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/main-page/team-members-avatars.webp similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/main-page/team-members-avatars.webp rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/main-page/team-members-avatars.webp diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/main-page/team-work-pic.webp b/src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/main-page/team-work-pic.webp similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/main-page/team-work-pic.webp rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/main-page/team-work-pic.webp diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/main-page/tick-icon-blue.svg b/src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/main-page/tick-icon-blue.svg similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/main-page/tick-icon-blue.svg rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/main-page/tick-icon-blue.svg diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/main-page/watch-icon.svg b/src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/main-page/watch-icon.svg similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/main-page/watch-icon.svg rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/main-page/watch-icon.svg diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/main-page/yaser-moradi-pic.webp b/src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/main-page/yaser-moradi-pic.webp similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/main-page/yaser-moradi-pic.webp rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/main-page/yaser-moradi-pic.webp diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/main-page/zahra-ebrahimi-pic.webp b/src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/main-page/zahra-ebrahimi-pic.webp similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/main-page/zahra-ebrahimi-pic.webp rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/main-page/zahra-ebrahimi-pic.webp diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/shared/bit-icon.svg b/src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/shared/bit-icon.svg similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/shared/bit-icon.svg rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/shared/bit-icon.svg diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/ui-effect/rocket-img.svg b/src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/ui-effect/rocket-img.svg similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/ui-effect/rocket-img.svg rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/ui-effect/rocket-img.svg diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/ui-effect/ui-effect-bell.svg b/src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/ui-effect/ui-effect-bell.svg similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/ui-effect/ui-effect-bell.svg rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/ui-effect/ui-effect-bell.svg diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/ui-effect/ui-effect-img-01.svg b/src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/ui-effect/ui-effect-img-01.svg similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/ui-effect/ui-effect-img-01.svg rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/ui-effect/ui-effect-img-01.svg diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/ui-effect/ui-effect-img-02.svg b/src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/ui-effect/ui-effect-img-02.svg similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/ui-effect/ui-effect-img-02.svg rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/ui-effect/ui-effect-img-02.svg diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/ui-effect/ui-effect-img-03.svg b/src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/ui-effect/ui-effect-img-03.svg similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/ui-effect/ui-effect-img-03.svg rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/ui-effect/ui-effect-img-03.svg diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/ui-effect/ui-effect-img-04.svg b/src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/ui-effect/ui-effect-img-04.svg similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/ui-effect/ui-effect-img-04.svg rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/ui-effect/ui-effect-img-04.svg diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/ui-effect/ui-effect-img-05.svg b/src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/ui-effect/ui-effect-img-05.svg similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/wwwroot/images/ui-effect/ui-effect-img-05.svg rename to src/Websites/Careers/src/Bit.Websites.Careers.Client/wwwroot/images/ui-effect/ui-effect-img-05.svg diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Server/AppSettings.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Server/AppSettings.cs new file mode 100644 index 0000000000..3d18c39570 --- /dev/null +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Server/AppSettings.cs @@ -0,0 +1,11 @@ +namespace Bit.Websites.Careers.Server; + +public class AppSettings +{ + public HealthCheckSettings HealthCheckSettings { get; set; } = default!; +} + +public class HealthCheckSettings +{ + public bool EnableHealthChecks { get; set; } +} diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Server/Bit.Websites.Careers.Server.csproj b/src/Websites/Careers/src/Bit.Websites.Careers.Server/Bit.Websites.Careers.Server.csproj new file mode 100644 index 0000000000..3e15a81e8e --- /dev/null +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Server/Bit.Websites.Careers.Server.csproj @@ -0,0 +1,53 @@ + + + + net8.0 + enable + enable + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + + + + + Always + + + + + + True + True + $([System.String]::Copy('%(Filename)').Replace('.Designer','')).resx + + + PublicResXFileCodeGenerator + %(Filename).Designer.cs + + + + diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Server/Components/App.razor b/src/Websites/Careers/src/Bit.Websites.Careers.Server/Components/App.razor new file mode 100644 index 0000000000..77f6340040 --- /dev/null +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Server/Components/App.razor @@ -0,0 +1,35 @@ +@using Bit.Websites.Careers.Client.Services + + + + + + + + + + + + + + + + + + + + + + + + + @if (HttpContext.Request.IsCrawlerClient() is false) + { + + + + } + + + + diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Server/Components/App.razor.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Server/Components/App.razor.cs new file mode 100644 index 0000000000..190da58877 --- /dev/null +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Server/Components/App.razor.cs @@ -0,0 +1,23 @@ +using Microsoft.AspNetCore.Components; + +namespace Bit.Websites.Careers.Server.Components; + +[StreamRendering(enabled: true)] +public partial class App +{ + [CascadingParameter] HttpContext HttpContext { get; set; } = default!; + + protected override void OnInitialized() + { + HttpContext.Response.OnStarting(async _ => + { + HttpContext.Response.GetTypedHeaders().CacheControl = new() + { + MaxAge = TimeSpan.FromDays(7), + Public = true + }; + }, null!); + + base.OnInitialized(); + } +} diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Server/Components/_Imports.razor b/src/Websites/Careers/src/Bit.Websites.Careers.Server/Components/_Imports.razor new file mode 100644 index 0000000000..893b26ee89 --- /dev/null +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Server/Components/_Imports.razor @@ -0,0 +1,6 @@ +@using System +@using Microsoft.Extensions.Localization +@using Microsoft.AspNetCore.Components.Web +@using Bit.Websites.Careers.Client +@using Bit.Websites.Careers.Client.Shared +@using Bit.BlazorUI \ No newline at end of file diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Extensions/HttpRequestExtensions.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Server/Extensions/HttpRequestExtensions.cs similarity index 90% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/Extensions/HttpRequestExtensions.cs rename to src/Websites/Careers/src/Bit.Websites.Careers.Server/Extensions/HttpRequestExtensions.cs index ad186f2799..12760a7e32 100644 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Extensions/HttpRequestExtensions.cs +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Server/Extensions/HttpRequestExtensions.cs @@ -18,7 +18,7 @@ public static string GetBaseUrl(this HttpRequest req) return uriBuilder.Uri.AbsoluteUri; } - public static bool ShouldRenderStaticMode(this HttpRequest request) + public static bool IsCrawlerClient(this HttpRequest request) { var agent = GetLoweredUserAgent(request); @@ -37,6 +37,6 @@ private static string GetLoweredUserAgent(HttpRequest request) if (string.IsNullOrEmpty(userAgent)) return string.Empty; - return userAgent.ToLower(); + return userAgent.ToLowerInvariant(); } } diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Server/Extensions/IServiceCollectionExtensions.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Server/Extensions/IServiceCollectionExtensions.cs new file mode 100644 index 0000000000..87a24c88c9 --- /dev/null +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Server/Extensions/IServiceCollectionExtensions.cs @@ -0,0 +1,72 @@ +using Microsoft.AspNetCore.Components.WebAssembly.Services; +using Microsoft.OpenApi.Models; +using Bit.Websites.Careers.Server; +using Bit.Websites.Careers.Client.Services.HttpMessageHandlers; + +namespace Microsoft.Extensions.DependencyInjection; + +public static class IServiceCollectionExtensions +{ + public static void AddBlazor(this IServiceCollection services, IConfiguration configuration) + { + services.AddScoped(sp => + { + IHttpClientFactory httpClientFactory = sp.GetRequiredService(); + return httpClientFactory.CreateClient("BlazorHttpClient"); + // This registers HttpClient for pre rendering & blazor server only, so to use http client to call 3rd party apis and other use cases, + // either use services.AddHttpClient("NamedHttpClient") or services.AddHttpClient(); + }); + + // In the Pre-Rendering mode, the configured HttpClient will use the access_token provided by the cookie in the request, so the pre-rendered content would be fitting for the current user. + services.AddHttpClient("BlazorHttpClient") + .AddHttpMessageHandler(sp => new RetryDelegatingHandler()) + .AddHttpMessageHandler(sp => new ExceptionDelegatingHandler()) + .ConfigurePrimaryHttpMessageHandler() + .ConfigureHttpClient((sp, httpClient) => + { + Uri.TryCreate(configuration.GetApiServerAddress(), UriKind.RelativeOrAbsolute, out var apiServerAddress); + + if (apiServerAddress!.IsAbsoluteUri is false) + { + apiServerAddress = new Uri($"{sp.GetRequiredService().HttpContext!.Request.GetBaseUrl()}{apiServerAddress}"); + } + + httpClient.BaseAddress = apiServerAddress; + }); + + services.AddScoped(); + + services.AddRazorComponents() + .AddInteractiveServerComponents() + .AddInteractiveWebAssemblyComponents(); + } + + public static void AddSwaggerGen(this IServiceCollection services) + { + services.AddSwaggerGen(options => + { + options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, "Bit.Websites.Careers.Server.xml")); + options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, "Bit.Websites.Careers.Shared.xml")); + }); + } + + public static void AddHealthChecks(this IServiceCollection services, IWebHostEnvironment env, IConfiguration configuration) + { + var appSettings = configuration.GetSection(nameof(AppSettings)).Get()!; + + var healthCheckSettings = appSettings.HealthCheckSettings; + + if (healthCheckSettings.EnableHealthChecks is false) + return; + + services.AddHealthChecksUI(setupSettings: setup => + { + setup.AddHealthCheckEndpoint("WebHealthChecks", env.IsDevelopment() ? "https://localhost:5051/healthz" : "/healthz"); + }).AddInMemoryStorage(); + + var healthChecksBuilder = services.AddHealthChecks() + .AddProcessAllocatedMemoryHealthCheck(maximumMegabytesAllocated: 6 * 1024) + .AddDiskStorageHealthCheck(opt => + opt.AddDrive(Path.GetPathRoot(Directory.GetCurrentDirectory())!, minimumFreeMegabytes: 5 * 1024)); + } +} diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Server/Mappers/Readme.md b/src/Websites/Careers/src/Bit.Websites.Careers.Server/Mappers/Readme.md new file mode 100644 index 0000000000..03523e9752 --- /dev/null +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Server/Mappers/Readme.md @@ -0,0 +1,17 @@ +When you have an IQueryable of an Entity or Model classes from EntityFrameworkCore, +you ultimately need to convert it into an IQueryable of DTO classes and return it to the client. +The client can also implement pagination during the API call by sending values for $top, $skip and sort by $orderby in query string. +Ultimately, the query is executed by aspnetcore and the data gets streamed from the database to the client, which is the most optimal case. +For this, you need to write a `Project` for each Entity you intend to return a query of DTO class from. + +You also write a `Map` for when a DTO is sent to the server for create or update api, +so you can convert it to an Entity and save it in the database using ef core. +You also need a Map method to convert DTO to Entity and vice versa. + +You also need a `Patch` method for the update scenario, to perform update operation, first get the Entity from the database with its Id, +then patch the latest changes from the DTO sent by the client, and finally save it. + +These methods (`Project`, `Map` and `Patch`) are gets called in controllers. + +For more information and to learn about customizing the mapping process, visit the website below: +https://mapperly.riok.app/docs/intro/ \ No newline at end of file diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Server/Program.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Server/Program.cs new file mode 100644 index 0000000000..d4747c3a6a --- /dev/null +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Server/Program.cs @@ -0,0 +1,12 @@ +var builder = WebApplication.CreateBuilder(args); + +// We need to load the client app configurations to prerender the app on server side. +builder.Configuration.AddClientConfigurations(); + +Bit.Websites.Careers.Server.Startup.Services.Add(builder.Services, builder.Environment, builder.Configuration); + +var app = builder.Build(); + +Bit.Websites.Careers.Server.Startup.Middlewares.Use(app, builder.Environment, builder.Configuration); + +app.Run(); diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Api/Properties/launchSettings.json b/src/Websites/Careers/src/Bit.Websites.Careers.Server/Properties/launchSettings.json similarity index 63% rename from src/Websites/Sales/src/Bit.Websites.Sales.Api/Properties/launchSettings.json rename to src/Websites/Careers/src/Bit.Websites.Careers.Server/Properties/launchSettings.json index a474ac2b34..404cc312bd 100644 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Api/Properties/launchSettings.json +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Server/Properties/launchSettings.json @@ -1,22 +1,21 @@ { + "$schema": "http://json.schemastore.org/launchsettings.json", "profiles": { - "Bit.Websites.Sales.Api": { + "Bit.Websites.Careers": { "commandName": "Project", "dotnetRunMessages": true, "launchBrowser": true, - "applicationUrl": "https://localhost:5021;http://localhost:5020", - "launchUrl": "swagger", + "applicationUrl": "http://localhost:5050;https://localhost:5051", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } }, - // This configuration allows debugging the Blazor WebAssembly - "Bit.Websites.Sales.Api-BlazorWebAssembly": { + "Bit.Websites.Careers + WASM debugging": { "commandName": "Project", "dotnetRunMessages": true, "launchBrowser": true, "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", - "applicationUrl": "https://localhost:5021;http://localhost:5020", + "applicationUrl": "http://localhost:5050;https://localhost:5051", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Server/Services/ApiExceptionHandler.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Server/Services/ApiExceptionHandler.cs new file mode 100644 index 0000000000..03bad06f35 --- /dev/null +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Server/Services/ApiExceptionHandler.cs @@ -0,0 +1,50 @@ +using System.Net; +using System.Reflection; +using Microsoft.AspNetCore.Diagnostics; + +namespace Bit.Websites.Careers.Server.Services; + +public partial class ApiExceptionHandler : IExceptionHandler +{ + [AutoInject] private IWebHostEnvironment _webHostEnvironment = default!; + + public async ValueTask TryHandleAsync(HttpContext httpContext, Exception e, CancellationToken cancellationToken) + { + // Using the Request-Id header, one can find the log for server-related exceptions + httpContext.Response.Headers.Append("Request-ID", httpContext.TraceIdentifier); + + var exception = UnWrapException(e); + var knownException = exception as KnownException; + + // The details of all of the exceptions are returned only in dev mode. in any other modes like production, only the details of the known exceptions are returned. + var key = knownException?.Key ?? nameof(UnknownException); + var message = knownException?.Message ?? (_webHostEnvironment.IsDevelopment() ? exception.Message : nameof(UnknownException)); + + var statusCode = (int)(exception is RestException restExp ? restExp.StatusCode : HttpStatusCode.InternalServerError); + + var restExceptionPayload = new RestErrorInfo + { + Key = key, + Message = message, + ExceptionType = knownException?.GetType().FullName ?? typeof(UnknownException).FullName + }; + + if (exception is ResourceValidationException validationException) + { + restExceptionPayload.Payload = validationException.Payload; + } + + httpContext.Response.StatusCode = statusCode; + + await httpContext.Response.WriteAsJsonAsync(restExceptionPayload, AppJsonContext.Default.RestErrorInfo, cancellationToken: cancellationToken); + + return true; + } + + private Exception UnWrapException(Exception exp) + { + return exp is TargetInvocationException && exp.InnerException is not null + ? exp.InnerException + : exp; + } +} diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Server/Services/NullAntiforgery.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Server/Services/NullAntiforgery.cs new file mode 100644 index 0000000000..2974066f0d --- /dev/null +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Server/Services/NullAntiforgery.cs @@ -0,0 +1,22 @@ +using Microsoft.AspNetCore.Antiforgery; + +namespace Bit.Websites.Careers.Server.Services; + +public class NullAntiforgery : IAntiforgery +{ + private const string AntiforgeryTokenFieldName = "__RequestVerificationToken"; + private const string AntiforgeryTokenHeaderName = "RequestVerificationToken"; + + public AntiforgeryTokenSet GetAndStoreTokens(HttpContext httpContext) => new(string.Empty, string.Empty, AntiforgeryTokenFieldName, AntiforgeryTokenHeaderName); + + public AntiforgeryTokenSet GetTokens(HttpContext httpContext) => new(string.Empty, string.Empty, AntiforgeryTokenFieldName, AntiforgeryTokenHeaderName); + + public Task IsRequestValidAsync(HttpContext httpContext) => Task.FromResult(true); + + public void SetCookieTokenAndHeader(HttpContext httpContext) + { + return; + } + + public Task ValidateRequestAsync(HttpContext httpContext) => Task.FromResult(true); +} diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Server/Startup/Middlewares.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Server/Startup/Middlewares.cs new file mode 100644 index 0000000000..534a2c0549 --- /dev/null +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Server/Startup/Middlewares.cs @@ -0,0 +1,85 @@ +using System.Reflection; +using Bit.Websites.Careers.Server.Components; +using HealthChecks.UI.Client; +using Microsoft.AspNetCore.Diagnostics.HealthChecks; +using Microsoft.AspNetCore.Http.Extensions; +using Microsoft.Net.Http.Headers; + +namespace Bit.Websites.Careers.Server.Startup; + +public class Middlewares +{ + public static void Use(WebApplication app, IHostEnvironment env, IConfiguration configuration) + { + app.UseForwardedHeaders(); + + if (env.IsDevelopment()) + { + app.UseWebAssemblyDebugging(); + } + else + { + app.UseHttpsRedirection(); + app.UseResponseCompression(); + } + + app.UseStatusCodePages(options: new() + { + HandleAsync = async (statusCodeContext) => + { + var httpContext = statusCodeContext.HttpContext; + + if (httpContext.Response.StatusCode is 404) + { + httpContext.Response.Redirect($"not-found?url={httpContext.Request.GetEncodedPathAndQuery()}"); + } + else if (httpContext.Response.StatusCode is 401) + { + httpContext.Response.Redirect($"not-authorized?redirectUrl={httpContext.Request.GetEncodedPathAndQuery()}"); + } + } + }); + + app.UseStaticFiles(new StaticFileOptions + { + OnPrepareResponse = ctx => + { + // https://bitplatform.dev/templates/cache-mechanism + ctx.Context.Response.GetTypedHeaders().CacheControl = new CacheControlHeaderValue() + { + MaxAge = TimeSpan.FromDays(7), + Public = true + }; + } + }); + + app.UseResponseCaching(); + app.UseAntiforgery(); + + app.UseExceptionHandler("/", createScopeForErrors: true); + app.UseSwagger(); + + app.UseSwaggerUI(); + + app.MapControllers(); + + var appSettings = configuration.GetSection(nameof(AppSettings)).Get()!; + + var healthCheckSettings = appSettings.HealthCheckSettings; + + if (healthCheckSettings.EnableHealthChecks) + { + app.MapHealthChecks("/healthz", new HealthCheckOptions + { + ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse + }); + + app.MapHealthChecksUI(); + } + + app.MapRazorComponents() + .AddInteractiveServerRenderMode() + .AddInteractiveWebAssemblyRenderMode() + .AddAdditionalAssemblies(Assembly.Load("Bit.Websites.Careers.Client")); + } +} diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Server/Startup/Services.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Server/Startup/Services.cs new file mode 100644 index 0000000000..7827c4a86e --- /dev/null +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Server/Startup/Services.cs @@ -0,0 +1,58 @@ +using System.IO.Compression; +using Microsoft.AspNetCore.HttpOverrides; +using Microsoft.AspNetCore.ResponseCompression; +using Bit.Websites.Careers.Server.Services; +using Microsoft.AspNetCore.Antiforgery; + +namespace Bit.Websites.Careers.Server.Startup; + +public static class Services +{ + public static void Add(IServiceCollection services, IWebHostEnvironment env, IConfiguration configuration) + { + // Services being registered here can get injected into controllers and services in Api project. + + var appSettings = configuration.GetSection(nameof(AppSettings)).Get()!; + + services.AddTransient(); + + services.AddClientSharedServices(); + + services.AddExceptionHandler(); + + services.AddBlazor(configuration); + + services + .AddControllers(); + + services.Configure(options => + { + options.ForwardedHeaders = ForwardedHeaders.All; + options.ForwardedHostHeaderName = "X-Host"; + }); + + services.AddResponseCaching(); + + services.AddHttpContextAccessor(); + + services.AddResponseCompression(opts => + { + opts.EnableForHttps = true; + opts.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(["application/octet-stream"]).ToArray(); + opts.Providers.Add(); + opts.Providers.Add(); + }) + .Configure(opt => opt.Level = CompressionLevel.Fastest) + .Configure(opt => opt.Level = CompressionLevel.Fastest); + + services.Configure(configuration.GetSection(nameof(AppSettings))); + + services.AddScoped(sp => sp.GetRequiredService>().Value); + + services.AddEndpointsApiExplorer(); + + services.AddSwaggerGen(); + + services.AddHealthChecks(env, configuration); + } +} diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Server/appsettings.Development.json b/src/Websites/Careers/src/Bit.Websites.Careers.Server/appsettings.Development.json new file mode 100644 index 0000000000..f3f302cced --- /dev/null +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Server/appsettings.Development.json @@ -0,0 +1,5 @@ +{ + "AppSettings": { + + } +} \ No newline at end of file diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Api/appsettings.json b/src/Websites/Careers/src/Bit.Websites.Careers.Server/appsettings.json similarity index 76% rename from src/Websites/Careers/src/Bit.Websites.Careers.Api/appsettings.json rename to src/Websites/Careers/src/Bit.Websites.Careers.Server/appsettings.json index ad8c25308c..5494283715 100644 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Api/appsettings.json +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Server/appsettings.json @@ -9,10 +9,11 @@ "AppSettings": { "HealthCheckSettings": { "EnableHealthChecks": false + }, + "TelegramBotSettings": { + "Token": "", + "ChatIds": [ "" ] } }, - "GoogleTagManager": { - "Id": "" - }, "AllowedHosts": "*" } diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Api/wwwroot/images/icon.png b/src/Websites/Careers/src/Bit.Websites.Careers.Server/wwwroot/images/icon.png similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Api/wwwroot/images/icon.png rename to src/Websites/Careers/src/Bit.Websites.Careers.Server/wwwroot/images/icon.png diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Attributes/DtoResourceTypeAttribute.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Attributes/DtoResourceTypeAttribute.cs deleted file mode 100644 index 111b40c0b8..0000000000 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Attributes/DtoResourceTypeAttribute.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Bit.Websites.Careers.Shared.Attributes; - -/// -/// Gets or sets the resource type to use for error message & localizations lookups. -/// -public class DtoResourceTypeAttribute : Attribute -{ - public Type ResourceType { get; } - - public DtoResourceTypeAttribute(Type resourceType) - { - ResourceType = resourceType ?? throw new ArgumentNullException(nameof(resourceType)); - } -} diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Bit.Websites.Careers.Shared.csproj b/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Bit.Websites.Careers.Shared.csproj index 64612bacfb..96dbf45ddf 100644 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Bit.Websites.Careers.Shared.csproj +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Bit.Websites.Careers.Shared.csproj @@ -1,6 +1,8 @@  + net8.0 + en-US @@ -12,10 +14,28 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - - + + compile; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + True + True + $([System.String]::Copy('%(Filename)').Replace('.Designer','')).resx + + + PublicResXFileCodeGenerator + %(Filename).Designer.cs + + + diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Dtos/AppJsonContext.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Dtos/AppJsonContext.cs index c3dc2d9280..a961dd7d8f 100644 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Dtos/AppJsonContext.cs +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Dtos/AppJsonContext.cs @@ -4,6 +4,7 @@ /// https://devblogs.microsoft.com/dotnet/try-the-new-system-text-json-source-generator/ ///
[JsonSourceGenerationOptions(PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase)] +[JsonSerializable(typeof(Dictionary))] [JsonSerializable(typeof(RestErrorInfo))] public partial class AppJsonContext : JsonSerializerContext { diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Exceptions/BadRequestException.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Exceptions/BadRequestException.cs index a2d998a553..b180bfc5a2 100644 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Exceptions/BadRequestException.cs +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Exceptions/BadRequestException.cs @@ -4,6 +4,11 @@ namespace Bit.Websites.Careers.Shared.Exceptions; public class BadRequestException : RestException { + public BadRequestException() + : base(nameof(BadRequestException)) + { + } + public BadRequestException(string message) : base(message) { diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Exceptions/ConflictException.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Exceptions/ConflictException.cs index 45b09bc6e7..5c81854772 100644 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Exceptions/ConflictException.cs +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Exceptions/ConflictException.cs @@ -4,12 +4,17 @@ namespace Bit.Websites.Careers.Shared.Exceptions; public class ConflictException : RestException { + public ConflictException() + : this(nameof(ConflictException)) + { + } + public ConflictException(string message) : base(message) { } - public ConflictException(LocalizedString message, Exception? innerException) + public ConflictException(string message, Exception? innerException) : base(message, innerException) { } diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Exceptions/ErrorResourcePayload.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Exceptions/ErrorResourcePayload.cs index 94eb2d49bc..9ee0aeb6ab 100644 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Exceptions/ErrorResourcePayload.cs +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Exceptions/ErrorResourcePayload.cs @@ -4,14 +4,14 @@ public class ErrorResourcePayload { public string? ResourceTypeName { get; set; } = "*"; - public List Details { get; set; } = new(); + public List Details { get; set; } = []; } public class PropertyErrorResourceCollection { public string? Name { get; set; } = "*"; - public List Errors { get; set; } = new(); + public List Errors { get; set; } = []; } public class ErrorResource diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Exceptions/ForbiddenException.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Exceptions/ForbiddenException.cs deleted file mode 100644 index 49880a6605..0000000000 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Exceptions/ForbiddenException.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.Net; - -namespace Bit.Websites.Careers.Shared.Exceptions; - -public class ForbiddenException : RestException -{ - public ForbiddenException(string message) - : base(message) - { - } - - public ForbiddenException(string message, Exception? innerException) - : base(message, innerException) - { - } - - public override HttpStatusCode StatusCode => HttpStatusCode.Forbidden; -} diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Exceptions/ResourceNotFoundException.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Exceptions/ResourceNotFoundException.cs index 42de9e6013..2540dbc320 100644 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Exceptions/ResourceNotFoundException.cs +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Exceptions/ResourceNotFoundException.cs @@ -4,6 +4,11 @@ namespace Bit.Websites.Careers.Shared.Exceptions; public class ResourceNotFoundException : RestException { + public ResourceNotFoundException() + : base(nameof(ResourceNotFoundException)) + { + } + public ResourceNotFoundException(string message) : base(message) { diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Exceptions/ResourceValidationException.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Exceptions/ResourceValidationException.cs index dd2b71acde..8b97c34943 100644 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Exceptions/ResourceValidationException.cs +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Exceptions/ResourceValidationException.cs @@ -4,42 +4,6 @@ namespace Bit.Websites.Careers.Shared.Exceptions; public class ResourceValidationException : RestException { - public ResourceValidationException(params LocalizedString[] errorMessages) - : this(new[] { ("*", errorMessages) }) - { - - } - - public ResourceValidationException((string propName, LocalizedString[] errorMessages)[] details) - : this("*", details) - { - - } - - public ResourceValidationException(Type resourceType, (string propName, LocalizedString[] errorMessages)[] details) - : this(resourceType.FullName!, details) - { - - } - - public ResourceValidationException(string resourceTypeName, (string propName, LocalizedString[] errorMessages)[] details) - : this(new ErrorResourcePayload() - { - ResourceTypeName = resourceTypeName, - Details = details.Select(propErrors => new PropertyErrorResourceCollection - { - Name = propErrors.propName, - Errors = propErrors.errorMessages.Select(e => new ErrorResource() - { - Key = e.Name, - Message = e.Value - }).ToList() - }).ToList() - }) - { - - } - public ResourceValidationException(ErrorResourcePayload payload) : this(message: nameof(ResourceValidationException), payload) { diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Exceptions/RestErrorInfo.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Exceptions/RestErrorInfo.cs index b948aa4095..5fb54d2ac9 100644 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Exceptions/RestErrorInfo.cs +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Exceptions/RestErrorInfo.cs @@ -8,5 +8,5 @@ public class RestErrorInfo public string? Message { get; set; } - public ErrorResourcePayload Payload { get; set; } = new(); + public ErrorResourcePayload? Payload { get; set; } } diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Exceptions/RestException.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Exceptions/RestException.cs index c17baa8d49..5aacc8412a 100644 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Exceptions/RestException.cs +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Exceptions/RestException.cs @@ -4,6 +4,11 @@ namespace Bit.Websites.Careers.Shared.Exceptions; public class RestException : KnownException { + public RestException() + : base(nameof(RestException)) + { + } + public RestException(string message) : base(message) { diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Exceptions/ServerConnectionException.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Exceptions/ServerConnectionException.cs new file mode 100644 index 0000000000..81d7769e4b --- /dev/null +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Exceptions/ServerConnectionException.cs @@ -0,0 +1,18 @@ +namespace Bit.Websites.Careers.Shared.Exceptions; +public class ServerConnectionException : UnknownException +{ + public ServerConnectionException() + : base(nameof(ServerConnectionException)) + { + } + + public ServerConnectionException(string message) + : base(message) + { + } + + public ServerConnectionException(string message, Exception innerException) + : base(message, innerException) + { + } +} diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Exceptions/TooManyRequestsExceptions.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Exceptions/TooManyRequestsExceptions.cs index dfa6c5cf5b..be322e8747 100644 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Exceptions/TooManyRequestsExceptions.cs +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Exceptions/TooManyRequestsExceptions.cs @@ -4,23 +4,17 @@ namespace Bit.Websites.Careers.Shared.Exceptions; public class TooManyRequestsExceptions : RestException { - - public TooManyRequestsExceptions(string message) - : base(message) - { - } - - public TooManyRequestsExceptions(string message, Exception? innerException) - : base(message, innerException) + public TooManyRequestsExceptions() + : base(nameof(TooManyRequestsExceptions)) { } - public TooManyRequestsExceptions(LocalizedString message) + public TooManyRequestsExceptions(string message) : base(message) { } - public TooManyRequestsExceptions(LocalizedString message, Exception? innerException) + public TooManyRequestsExceptions(string message, Exception? innerException) : base(message, innerException) { } diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Exceptions/UnauthorizedException.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Exceptions/UnauthorizedException.cs deleted file mode 100644 index 1e8dd69bca..0000000000 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Exceptions/UnauthorizedException.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.Net; - -namespace Bit.Websites.Careers.Shared.Exceptions; - -public class UnauthorizedException : RestException -{ - public UnauthorizedException(string message) - : base(message) - { - } - - public UnauthorizedException(string message, Exception? innerException) - : base(message, innerException) - { - } - - public override HttpStatusCode StatusCode => HttpStatusCode.Unauthorized; -} diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Exceptions/UnknownException.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Exceptions/UnknownException.cs index d10a0e617f..2e3b48933b 100644 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Exceptions/UnknownException.cs +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Exceptions/UnknownException.cs @@ -2,6 +2,11 @@ public class UnknownException : Exception { + public UnknownException() + : base(nameof(UnknownException)) + { + } + public UnknownException(string message) : base(message) { @@ -12,4 +17,3 @@ public UnknownException(string message, Exception innerException) { } } - diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Extensions/ClaimsPrincipalExtensions.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Extensions/ClaimsPrincipalExtensions.cs deleted file mode 100644 index 9929bc0776..0000000000 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Extensions/ClaimsPrincipalExtensions.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace System.Security.Claims; - -public static class ClaimsPrincipalExtensions -{ - public static int GetUserId(this ClaimsPrincipal claimsPrincipal) - { - return int.Parse(claimsPrincipal.FindFirst(ClaimTypes.NameIdentifier)!.Value); - } - - public static string GetUserName(this ClaimsPrincipal claimsPrincipal) - { - return claimsPrincipal.FindFirst(ClaimTypes.Name)!.Value; - } -} diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Extensions/IServiceCollectionExtensions.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Extensions/IServiceCollectionExtensions.cs index c8c7bca2f6..032175b882 100644 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Extensions/IServiceCollectionExtensions.cs +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Extensions/IServiceCollectionExtensions.cs @@ -4,14 +4,12 @@ namespace Microsoft.Extensions.DependencyInjection; public static class IServiceCollectionExtensions { - public static void AddSharedServices(this IServiceCollection services) + public static IServiceCollection AddSharedServices(this IServiceCollection services) { - // Services being registered here can get injected everywhere (Api & Web) - - services.AddLocalization(); - - services.AddAuthorizationCore(); + // Services being registered here can get injected everywhere (Api, Web, Android, iOS, Windows, macOS and Linux) services.AddSingleton(); + + return services; } } diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Extensions/LinqExtensions.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Extensions/LinqExtensions.cs new file mode 100644 index 0000000000..718221b8fc --- /dev/null +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Extensions/LinqExtensions.cs @@ -0,0 +1,39 @@ +using System.Linq.Expressions; + +namespace System.Collections.Generic; + +public static class LinqExtensions +{ + /// + /// https://extensionmethod.net/csharp/ienumerable-t/whereif + /// + public static IQueryable WhereIf(this IQueryable query, bool predicate, Expression> itemPredicate) + { + return predicate ? query.Where(itemPredicate) : query; + } + + public static IQueryable OrderByIf(this IQueryable query, bool predicate, Expression> keySelector) + { + return predicate ? query.OrderBy(keySelector) : query; + } + + public static IQueryable OrderByDescendingIf(this IQueryable query, bool predicate, Expression> keySelector) + { + return predicate ? query.OrderByDescending(keySelector) : query; + } + + public static IEnumerable WhereIf(this IEnumerable source, bool predicate, Func itemPredicate) + { + return predicate ? source.Where(itemPredicate) : source; + } + + public static IEnumerable OrderByIf(this IEnumerable source, bool predicate, Func keySelector) + { + return predicate ? source.OrderBy(keySelector) : source; + } + + public static IEnumerable OrderByDescendingIf(this IEnumerable source, bool predicate, Func keySelector) + { + return predicate ? source.OrderByDescending(keySelector) : source; + } +} diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Infra/BlazorMode.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Infra/BlazorMode.cs deleted file mode 100644 index b7ebb09248..0000000000 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Infra/BlazorMode.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Bit.Websites.Careers.Shared.Infra; - -public enum BlazorMode -{ - BlazorServer = 0, - BlazorWebAssembly = 1 -} diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Infra/BlazorModeDetector.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Infra/BlazorModeDetector.cs deleted file mode 100644 index 98d5576af0..0000000000 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Infra/BlazorModeDetector.cs +++ /dev/null @@ -1,31 +0,0 @@ -namespace Bit.Websites.Careers.Shared.Infra; - -/// -/// https://bitplatform.dev/templates/hosting-models -/// -public class BlazorModeDetector -{ - public static BlazorModeDetector Current { get; set; } = new BlazorModeDetector(); - - public virtual bool IsBlazorServer() - { - return Mode == BlazorMode.BlazorServer; - } - - public virtual bool IsBlazorWebAssembly() - { - return Mode == BlazorMode.BlazorWebAssembly; - } - - public virtual BlazorMode Mode - { - get - { -#if BlazorWebAssembly - return BlazorMode.BlazorWebAssembly; -#else - return BlazorMode.BlazorServer; -#endif - } - } -} diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Infra/CultureInfoManager.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Infra/CultureInfoManager.cs deleted file mode 100644 index 46c5de6f41..0000000000 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Infra/CultureInfoManager.cs +++ /dev/null @@ -1,103 +0,0 @@ -using System.Reflection; - -namespace Bit.Websites.Careers.Shared.Infra; -public class CultureInfoManager -{ - public static (string name, string code) DefaultCulture { get; } = ("English", "en-US"); - - public static (string name, string code)[] SupportedCultures { get; } = new (string name, string code)[] - { - ("English US", "en-US"), - ("English UK", "en-GB"), - ("Française", "fr-FR"), - // ("فارسی", "fa-IR"), // To add more languages, you've to provide resx files. You might also put some efforts to change your app flow direction based on CultureInfo.CurrentUICulture.TextInfo.IsRightToLeft - }; - - public static CultureInfo CreateCultureInfo(string cultureInfoId) - { - var cultureInfo = OperatingSystem.IsBrowser() ? CultureInfo.CreateSpecificCulture(cultureInfoId) : new CultureInfo(cultureInfoId); - - if (cultureInfoId == "fa-IR") - { - CustomizeCultureInfoForFaCulture(cultureInfo); - } - - return cultureInfo; - } - - public static void SetCurrentCulture(string? cultureInfoCookie) - { - var currentCulture = GetCurrentCulture(cultureInfoCookie); - - var cultureInfo = CreateCultureInfo(currentCulture); - - CultureInfo.CurrentCulture = CultureInfo.CurrentUICulture = CultureInfo.DefaultThreadCurrentCulture = CultureInfo.DefaultThreadCurrentUICulture = Thread.CurrentThread.CurrentCulture = Thread.CurrentThread.CurrentUICulture = cultureInfo; - } - - public static string GetCurrentCulture(string? preferredCultureCookie) - { - string culture = CultureInfo.CurrentUICulture.Name; - if (preferredCultureCookie is not null) - { - culture = preferredCultureCookie[(preferredCultureCookie.IndexOf("|uic=") + 5)..]; - } - if (SupportedCultures.Any(sc => sc.code == culture) is false) - { - culture = DefaultCulture.code; - } - return culture; - } - - /// - /// This is an example to demonstrate the way you can customize application culture - /// - public static CultureInfo CustomizeCultureInfoForFaCulture(CultureInfo cultureInfo) - { - cultureInfo.DateTimeFormat.MonthNames = new[] - { - "فروردین", "اردیبهشت", "خرداد", "تیر", "مرداد", "شهریور", "مهر", "آبان", "آذر", "دی", "بهمن", "اسفند", "" - }; - - cultureInfo.DateTimeFormat.AbbreviatedMonthNames = new[] - { - "فرور", "ارد", "خرد", "تیر", "مرد", "شهر", "مهر", "آبا", "آذر", "دی", "بهم", "اسف", "" - }; - - cultureInfo.DateTimeFormat.MonthGenitiveNames = cultureInfo.DateTimeFormat.MonthNames; - cultureInfo.DateTimeFormat.AbbreviatedMonthGenitiveNames = cultureInfo.DateTimeFormat.AbbreviatedMonthNames; - cultureInfo.DateTimeFormat.DayNames = new[] - { - "یکشنبه", "دوشنبه", "ﺳﻪشنبه", "چهارشنبه", "پنجشنبه", "جمعه", "شنبه" - }; - - cultureInfo.DateTimeFormat.AbbreviatedDayNames = new[] - { - "ی", "د", "س", "چ", "پ", "ج", "ش" - }; - - cultureInfo.DateTimeFormat.ShortestDayNames = new[] - { - "ی", "د", "س", "چ", "پ", "ج", "ش" - }; - - cultureInfo.DateTimeFormat.AMDesignator = "ق.ظ"; - cultureInfo.DateTimeFormat.PMDesignator = "ب.ظ"; - cultureInfo.DateTimeFormat.ShortDatePattern = "yyyy/MM/dd"; - cultureInfo.DateTimeFormat.FirstDayOfWeek = DayOfWeek.Saturday; - - var cultureData = _cultureDataField.GetValue(cultureInfo.TextInfo); - - _iReadingLayoutField.SetValue(cultureData, 1 /*rtl*/); // this affects cultureInfo.TextInfo.IsRightToLeft - - if (cultureInfo.DateTimeFormat.Calendar is not PersianCalendar) - { - cultureInfo.DateTimeFormat.Calendar = new PersianCalendar(); - } - - return cultureInfo; - } - - private static readonly FieldInfo _cultureDataField = typeof(TextInfo).GetField("_cultureData", BindingFlags.NonPublic | BindingFlags.Instance)!; - - private static readonly FieldInfo _iReadingLayoutField = Type.GetType("System.Globalization.CultureData, System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e")!.GetField("_iReadingLayout", BindingFlags.NonPublic | BindingFlags.Instance)!; -} diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Infra/WebAppDeploymentType.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Infra/WebAppDeploymentType.cs deleted file mode 100644 index 903ec9bd0a..0000000000 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Infra/WebAppDeploymentType.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Bit.Websites.Careers.Shared.Infra; - -public enum WebAppDeploymentType -{ - Default, - Ssr, - Static -} diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Infra/WebAppDeploymentTypeDetector.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Infra/WebAppDeploymentTypeDetector.cs deleted file mode 100644 index 34dc49f3fb..0000000000 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Infra/WebAppDeploymentTypeDetector.cs +++ /dev/null @@ -1,38 +0,0 @@ -namespace Bit.Websites.Careers.Shared.Infra; - -/// -/// https://bitplatform.dev/templates/hosting-models -/// -public class WebAppDeploymentTypeDetector -{ - public static WebAppDeploymentTypeDetector Current { get; set; } = new WebAppDeploymentTypeDetector(); - - public virtual bool IsDefault() - { - return Mode == WebAppDeploymentType.Default; - } - - public virtual bool IsStatic() - { - return Mode == WebAppDeploymentType.Static; - } - - public virtual bool IsSsr() - { - return Mode == WebAppDeploymentType.Ssr; - } - - public virtual WebAppDeploymentType Mode - { - get - { -#if SSR - return WebAppDeploymentType.Ssr; -#elif Static - return WebAppDeploymentType.Static; -#else - return WebAppDeploymentType.Default; -#endif - } - } -} diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Mapper.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Mapper.cs new file mode 100644 index 0000000000..51999487f4 --- /dev/null +++ b/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Mapper.cs @@ -0,0 +1,17 @@ +using Riok.Mapperly.Abstractions; + +namespace Bit.Websites.Careers.Shared; + +/// +/// Patching methods help you patch the DTO you have received from the server (for example, after calling an Update api) +/// onto the DTO you have bound to the UI. This way, the UI gets updated with the latest saved changes, +/// and there's no need to re-fetch that specific data from the server. +/// For complete end to end sample you can check EditProfilePage.razor.cs +/// You can add as many as Patch methods you want for other DTO classes here. +/// For more information and to learn about customizing the mapping process, visit the website below: +/// https://mapperly.riok.app/docs/intro/ +/// +[Mapper(UseDeepCloning = true)] +public static partial class Mapper +{ +} diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Services/Contracts/IAuthTokenProvider.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Services/Contracts/IAuthTokenProvider.cs deleted file mode 100644 index 0ffd24e321..0000000000 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Shared/Services/Contracts/IAuthTokenProvider.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Bit.Websites.Careers.Shared.Services.Contracts; - -public interface IAuthTokenProvider -{ - Task GetAccessTokenAsync(); -} diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/App.razor b/src/Websites/Careers/src/Bit.Websites.Careers.Web/App.razor deleted file mode 100644 index 5b4d4c9348..0000000000 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Web/App.razor +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/App.razor.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Web/App.razor.cs deleted file mode 100644 index 81b9806653..0000000000 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Web/App.razor.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace Bit.Websites.Careers.Web; - -public partial class App -{ -} diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Components/AppDataAnnotationsValidator.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Web/Components/AppDataAnnotationsValidator.cs deleted file mode 100644 index 6f10f428fa..0000000000 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Components/AppDataAnnotationsValidator.cs +++ /dev/null @@ -1,189 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; -using Microsoft.AspNetCore.Components.Forms; -using Bit.Websites.Careers.Shared.Attributes; - -namespace Bit.Websites.Careers.Web.Components; - -public partial class AppDataAnnotationsValidator : AppComponentBase, IDisposable -{ - private static readonly PropertyInfo _OtherPropertyNamePropertyInfo = - typeof(CompareAttribute).GetProperty(nameof(CompareAttribute.OtherPropertyDisplayName))!; - - private bool _disposed; - private ValidationMessageStore _validationMessageStore = default!; - - [AutoInject] private IServiceProvider _serviceProvider = default!; - [AutoInject] private IStringLocalizerFactory _stringLocalizerFactory = default!; - - [CascadingParameter] private EditContext _editContext { get; set; } = default!; - - protected override Task OnInitAsync() - { - if (_editContext is null) - throw new InvalidOperationException("EditContext is required"); - - _editContext.OnFieldChanged += OnFieldChanged; - _editContext.OnValidationRequested += OnValidationRequested; - - _validationMessageStore = new ValidationMessageStore(_editContext); - - return base.OnInitAsync(); - } - - private void OnFieldChanged(object? sender, FieldChangedEventArgs eventArgs) - { - var fieldIdentifier = eventArgs.FieldIdentifier; - var propertyInfo = fieldIdentifier.Model.GetType().GetProperty(fieldIdentifier.FieldName); - if (propertyInfo is null) return; - - var propertyValue = propertyInfo.GetValue(fieldIdentifier.Model); - var validationContext = new ValidationContext(fieldIdentifier.Model, _serviceProvider, items: null) - { - MemberName = propertyInfo.Name - }; - var results = new List(); - - var parent = propertyInfo.DeclaringType!; - var dtoResourceTypeAttr = parent.GetCustomAttribute(); - if (dtoResourceTypeAttr is null) - { - Validator.TryValidateProperty(propertyValue, validationContext, results); - } - else - { - var resourceType = dtoResourceTypeAttr.ResourceType; - var stringLocalizer = _stringLocalizerFactory.Create(resourceType); - var validationAttributes = propertyInfo.GetCustomAttributes(); - - foreach (var attribute in validationAttributes) - { - if (string.IsNullOrWhiteSpace(attribute.ErrorMessageResourceName) is false && attribute.ErrorMessageResourceType is null) - { - attribute.ErrorMessageResourceType = resourceType; - var displayAttribute = propertyInfo.GetCustomAttribute(); - validationContext.DisplayName = stringLocalizer.GetString(displayAttribute?.Name ?? propertyInfo.Name); - - if (attribute is CompareAttribute compareAttribute) - { - var otherPropertyInfoDisplayAttribute = (parent.GetProperty(compareAttribute.OtherProperty) ?? throw new InvalidOperationException($"Invalid OtherProperty {compareAttribute.OtherProperty}")).GetCustomAttribute(); - _OtherPropertyNamePropertyInfo.SetValue(attribute, stringLocalizer.GetString(otherPropertyInfoDisplayAttribute?.Name ?? compareAttribute.OtherProperty).ToString()); - } - } - - var result = attribute.GetValidationResult(propertyValue, validationContext); - - if (result is not null) - { - results.Add(result); - } - } - - } - - _validationMessageStore.Clear(fieldIdentifier); - - foreach (var result in CollectionsMarshal.AsSpan(results)) - { - _validationMessageStore.Add(fieldIdentifier, result.ErrorMessage!); - } - - _editContext.NotifyValidationStateChanged(); - } - - private void OnValidationRequested(object? sender, ValidationRequestedEventArgs e) - { - var validationContext = new ValidationContext(_editContext.Model, _serviceProvider, items: null); - var results = new List(); - - var objectType = validationContext.ObjectType; - var objectInstance = validationContext.ObjectInstance; - var dtoResourceTypeAttr = objectType.GetCustomAttribute(); - - _validationMessageStore.Clear(); - - if (dtoResourceTypeAttr is null) - { - Validator.TryValidateObject(_editContext.Model, validationContext, results, true); - } - else - { - var resourceType = dtoResourceTypeAttr.ResourceType; - - var stringLocalizer = _stringLocalizerFactory.Create(resourceType); - - var properties = objectType.GetProperties(BindingFlags.Instance | BindingFlags.Public); - - foreach (var propertyInfo in properties) - { - var context = new ValidationContext(objectInstance, validationContext, validationContext.Items) { MemberName = propertyInfo.Name }; - var propertyValue = propertyInfo.GetValue(objectInstance); - var validationAttributes = propertyInfo.GetCustomAttributes(); - foreach (var attribute in validationAttributes) - { - if (string.IsNullOrWhiteSpace(attribute.ErrorMessageResourceName) is false && attribute.ErrorMessageResourceType is null) - { - attribute.ErrorMessageResourceType = resourceType; - var displayAttribute = propertyInfo.GetCustomAttribute(); - validationContext.DisplayName = stringLocalizer.GetString(displayAttribute?.Name ?? propertyInfo.Name); - if (attribute is CompareAttribute compareAttribute) - { - var otherPropertyInfoDisplayAttribute = (properties.FirstOrDefault(p => p.Name == compareAttribute.OtherProperty) - ?? throw new InvalidOperationException($"Invalid OtherProperty {compareAttribute.OtherProperty}")).GetCustomAttribute(); - - _OtherPropertyNamePropertyInfo.SetValue(attribute, stringLocalizer.GetString(otherPropertyInfoDisplayAttribute?.Name - ?? compareAttribute.OtherProperty).ToString()); - } - } - - var result = attribute.GetValidationResult(propertyValue, context); - - if (result is not null) - { - results.Add(result); - } - } - } - } - - _validationMessageStore.Clear(); - - foreach (var validationResult in results) - { - if (validationResult == null) continue; - - var hasMemberNames = false; - - foreach (var memberName in validationResult.MemberNames) - { - hasMemberNames = true; - _validationMessageStore.Add(_editContext.Field(memberName), validationResult.ErrorMessage!); - } - - if (hasMemberNames) continue; - - _validationMessageStore.Add(new FieldIdentifier(_editContext.Model, fieldName: string.Empty), validationResult.ErrorMessage!); - } - - _editContext.NotifyValidationStateChanged(); - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - protected virtual void Dispose(bool disposing) - { - if (_disposed || disposing is false) return; - - if (_editContext is not null) - { - _editContext.OnFieldChanged -= OnFieldChanged; - _editContext.OnValidationRequested -= OnValidationRequested; - } - - _disposed = true; - } -} diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Extensions/IConfigurationExtensions.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Web/Extensions/IConfigurationExtensions.cs deleted file mode 100644 index f3e0fe69bb..0000000000 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Extensions/IConfigurationExtensions.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Microsoft.Extensions.Configuration; -public static class IConfigurationExtensions -{ - public static string GetApiServerAddress(this IConfiguration configuration) - { - return configuration.GetValue("ApiServerAddress") ?? throw new InvalidOperationException("Could not find ApiServerAddress config"); - } -} diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Extensions/IServiceCollectionExtensions.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Web/Extensions/IServiceCollectionExtensions.cs deleted file mode 100644 index efa43dd30b..0000000000 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Extensions/IServiceCollectionExtensions.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace Microsoft.Extensions.DependencyInjection; - -public static class IServiceCollectionExtensions -{ - public static IServiceCollection AddClientSharedServices(this IServiceCollection services) - { - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - - services.AddTransient(); - - return services; - } -} diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Pages/BupProgressBar.razor b/src/Websites/Careers/src/Bit.Websites.Careers.Web/Pages/BupProgressBar.razor deleted file mode 100644 index b23dd8fb3c..0000000000 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Pages/BupProgressBar.razor +++ /dev/null @@ -1,49 +0,0 @@ -@using Bit.Bup -@using Bit.BlazorUI - - - -@code { - private bool _showLoading = true; - - protected override void OnAfterRender(bool firstRender) - { - base.OnAfterRender(firstRender); - if (firstRender is false) return; - - _showLoading = false; - StateHasChanged(); - } -} - -@if (_showLoading) -{ -
- -
- - -
-} \ No newline at end of file diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Pages/_Host.cshtml b/src/Websites/Careers/src/Bit.Websites.Careers.Web/Pages/_Host.cshtml deleted file mode 100644 index b02d1727af..0000000000 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Pages/_Host.cshtml +++ /dev/null @@ -1,30 +0,0 @@ -@page "/" -@using Bit.Websites.Careers.Web; -@using Bit.Websites.Careers.Shared.Infra; -@namespace Bit.Websites.Careers.Web.Pages -@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers -@{ - Layout = "_Layout"; - var isBlazorServer = BlazorModeDetector.Current.IsBlazorServer(); - var isDefaultDeploymentType = WebAppDeploymentTypeDetector.Current.IsDefault(); - var isStatic = WebAppDeploymentTypeDetector.Current.IsStatic(); - RenderMode renderMode = isStatic - ? RenderMode.Static - : isBlazorServer - ? isDefaultDeploymentType - ? RenderMode.Server - : RenderMode.ServerPrerendered - : isDefaultDeploymentType - ? RenderMode.WebAssembly - : RenderMode.WebAssemblyPrerendered; - - if (renderMode is RenderMode.ServerPrerendered or RenderMode.WebAssemblyPrerendered) - { - if (Request.ShouldRenderStaticMode()) - { - renderMode = RenderMode.Static; - } - } -} - - diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Pages/_Layout.cshtml b/src/Websites/Careers/src/Bit.Websites.Careers.Web/Pages/_Layout.cshtml deleted file mode 100644 index de00dcf837..0000000000 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Pages/_Layout.cshtml +++ /dev/null @@ -1,142 +0,0 @@ -@using Bit.Websites.Careers.Shared.Infra -@using Microsoft.AspNetCore.Components.Web -@using RenderMode = Microsoft.AspNetCore.Mvc.Rendering.RenderMode - -@namespace Bit.Websites.Careers.Web.Pages -@inject IHttpContextAccessor ContextAccessor -@inject IConfiguration Configuration -@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers -@{ - var gtmId = @Configuration.GetSection("GoogleTagManager")["Id"]; - var isBlazorServer = BlazorModeDetector.Current.IsBlazorServer(); - var isDefaultDeploymentType = WebAppDeploymentTypeDetector.Current.IsDefault(); - var isStatic = WebAppDeploymentTypeDetector.Current.IsStatic(); - var isSsr = WebAppDeploymentTypeDetector.Current.IsSsr(); - var shoudAddAspAppendVersion = true; - RenderMode renderMode = isBlazorServer ? RenderMode.ServerPrerendered : RenderMode.WebAssemblyPrerendered; - - if (renderMode is RenderMode.ServerPrerendered or RenderMode.WebAssemblyPrerendered) - { - var shouldRenderStaticMode = ContextAccessor?.HttpContext?.Request.ShouldRenderStaticMode(); - - if (shouldRenderStaticMode is not null && shouldRenderStaticMode.Value) - { - renderMode = RenderMode.Static; - isStatic = true; - } - } -} - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- @if (isDefaultDeploymentType) - { - - } - @RenderBody() -
- - @if (isStatic is false) - { - @if (isBlazorServer) - { - - } - else - { - - - - - @if (isSsr) - { - - } - else - { - - - } - } - - } - - - @if (isSsr) - { - - } - - \ No newline at end of file diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Program.BlazorServer.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Web/Program.BlazorServer.cs deleted file mode 100644 index 9a0644b290..0000000000 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Program.BlazorServer.cs +++ /dev/null @@ -1,23 +0,0 @@ -#if BlazorServer -#endif - -namespace Bit.Websites.Careers.Web; - -public partial class Program -{ -#if BlazorServer - public static WebApplication CreateHostBuilder(string[] args) - { - var builder = WebApplication.CreateBuilder(args); - builder.Configuration.AddJsonStream(typeof(MainLayout).Assembly.GetManifestResourceStream("Bit.Websites.Careers.Web.appsettings.json")!); - - Startup.Services.Add(builder.Services, builder.Configuration); - - var app = builder.Build(); - - Startup.Middlewares.Use(app, builder.Environment); - - return app; - } -#endif -} diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Program.BlazorWebAssembly.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Web/Program.BlazorWebAssembly.cs deleted file mode 100644 index abf438d049..0000000000 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Program.BlazorWebAssembly.cs +++ /dev/null @@ -1,37 +0,0 @@ -#if BlazorWebAssembly -using Microsoft.AspNetCore.Components.WebAssembly.Hosting; -#endif - -namespace Bit.Websites.Careers.Web; - -public partial class Program -{ -#if BlazorWebAssembly - public static WebAssemblyHost CreateHostBuilder(string[] args) - { - var builder = WebAssemblyHostBuilder.CreateDefault(); - builder.Configuration.AddJsonStream(typeof(MainLayout).Assembly.GetManifestResourceStream("Bit.Websites.Careers.Web.appsettings.json")); - - if (Uri.TryCreate(builder.Configuration.GetApiServerAddress(), UriKind.RelativeOrAbsolute, out var apiServerAddress) is false) - { - throw new InvalidOperationException("Api server address is invalid"); - } - - if (apiServerAddress.IsAbsoluteUri is false) - { - apiServerAddress = new Uri($"{builder.HostEnvironment.BaseAddress}{apiServerAddress}"); - } - - builder.Services.AddSingleton(sp => new HttpClient(sp.GetRequiredService()) { BaseAddress = apiServerAddress }); - builder.Services.AddScoped(); - builder.Services.AddTransient(); - - builder.Services.AddSharedServices(); - builder.Services.AddClientSharedServices(); - - var host = builder.Build(); - - return host; - } -#endif -} diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Program.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Web/Program.cs deleted file mode 100644 index d9d96a744f..0000000000 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Program.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Bit.Websites.Careers.Web; - -public partial class Program -{ - public static async Task Main(string[] args) - { -#if !BlazorWebAssembly && !BlazorServer - throw new InvalidOperationException("Please switch to either blazor webassembly or server as described in readme.md"); -#else - await CreateHostBuilder(args) - .RunAsync(); -#endif - } -} diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Properties/launchSettings.json b/src/Websites/Careers/src/Bit.Websites.Careers.Web/Properties/launchSettings.json deleted file mode 100644 index 98d3811944..0000000000 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Properties/launchSettings.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "profiles": { - "Bit.Websites.Careers.Web": { - "commandName": "Project", - "dotnetRunMessages": true, - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - }, - "applicationUrl": "https://localhost:4001;http://localhost:4000" - } - } -} \ No newline at end of file diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Scripts/app.ts b/src/Websites/Careers/src/Bit.Websites.Careers.Web/Scripts/app.ts deleted file mode 100644 index f7c1b71987..0000000000 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Scripts/app.ts +++ /dev/null @@ -1,24 +0,0 @@ -class App { - public static setCookie(name: string, value: string, seconds: number) { - const date = new Date(); - date.setSeconds(date.getSeconds() + seconds); - document.cookie = `${name}=${value};expires=${date.toUTCString()};path=/`; - } - - public static getCookie(name: string): string | null { - // https://stackoverflow.com/a/25490531/2720104 - return document.cookie.match('(^|;)\\s*' + name + '\\s*=\\s*([^;]+)')?.pop() || null; - } - - public static removeCookie(name: string): void { - document.cookie = `${name}=; Max-Age=0`; - } - - public static goBack(): void { - window.history.back(); - } - - public static backToTop() { - window.scrollTo({ top: 0 }); - } -} \ No newline at end of file diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Services/AppHttpClientHandler.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Web/Services/AppHttpClientHandler.cs deleted file mode 100644 index 2bd058d84f..0000000000 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Services/AppHttpClientHandler.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System.Net.Http.Headers; - -namespace Bit.Websites.Careers.Web.Services; - -public partial class AppHttpClientHandler : HttpClientHandler -{ - [AutoInject] private IAuthTokenProvider _tokenProvider = default!; - - protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) - { - if (request.Headers.Authorization is null) - { - var access_token = await _tokenProvider.GetAccessTokenAsync(); - if (access_token is not null) - { - request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", access_token); - } - } - - var response = await base.SendAsync(request, cancellationToken); - - if (response.IsSuccessStatusCode is false && response.Content.Headers.ContentType?.MediaType?.Contains("application/json", StringComparison.InvariantCultureIgnoreCase) is true) - { - if (response.Headers.TryGetValues("Request-ID", out IEnumerable? values) && values is not null && values.Any()) - { - RestErrorInfo restError = await response.Content.ReadFromJsonAsync(AppJsonContext.Default.RestErrorInfo); - - Type exceptionType = typeof(RestErrorInfo).Assembly.GetType(restError.ExceptionType) ?? typeof(UnknownException); - - var args = new List { typeof(KnownException).IsAssignableFrom(exceptionType) ? new LocalizedString(restError.Key!, restError.Message!) : restError.Message }; - - if (exceptionType == typeof(ResourceValidationException)) - { - args.Add(restError.Payload); - } - - Exception exp = (Exception)Activator.CreateInstance(exceptionType, args.ToArray()); - - throw exp; - } - } - - response.EnsureSuccessStatusCode(); - - return response; - } -} diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Services/ClientSideAuthTokenProvider.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Web/Services/ClientSideAuthTokenProvider.cs deleted file mode 100644 index e36c682011..0000000000 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Services/ClientSideAuthTokenProvider.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Bit.Websites.Careers.Web.Services; - -public partial class ClientSideAuthTokenProvider : IAuthTokenProvider -{ - [AutoInject] private IJSRuntime _jsRuntime = default!; - - public async Task GetAccessTokenAsync() - { - return await _jsRuntime.InvokeAsync("App.getCookie", "access_token"); - } -} diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Services/Contracts/IPubSubService.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Web/Services/Contracts/IPubSubService.cs deleted file mode 100644 index 6146822204..0000000000 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Services/Contracts/IPubSubService.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Bit.Websites.Careers.Web.Services.Contracts; - -public interface IPubSubService -{ - void Pub(string message, object? payload); - Action Sub(string message, Action handler); -} diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Services/Contracts/IStateService.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Web/Services/Contracts/IStateService.cs deleted file mode 100644 index 1a1d8ca4b8..0000000000 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Services/Contracts/IStateService.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Bit.Websites.Careers.Web.Services.Contracts; - -public interface IStateService -{ - /// - /// Instead of using ApplicationState.TryTakeFromJson, ApplicationState.RegisterOnPersisting, and ApplicationState.PersistAsJson - /// (explained here: https://docs.microsoft.com/en-us/aspnet/core/blazor/components/prerendering-and-integration#persist-prerendered-state), - /// one can easily use the following method (StateService.GetValue) in the OnInit lifecycle method of the Blazor components - /// or pages to retrieve everything that requires an async-await (like current user's info). - /// - Task GetValue(string key, Func> factory); -} diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Services/ExceptionHandler.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Web/Services/ExceptionHandler.cs deleted file mode 100644 index 4766b2e251..0000000000 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Services/ExceptionHandler.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Bit.Websites.Careers.Web.Services; - -public partial class ExceptionHandler : IExceptionHandler -{ - public void Handle(Exception exception, IDictionary? parameters = null) - { - - } -} diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Services/PubSubMessages.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Web/Services/PubSubMessages.cs deleted file mode 100644 index 90368635ca..0000000000 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Services/PubSubMessages.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Bit.Websites.Careers.Web.Services; - -public static class PubSubMessages -{ - public const string PROFILE_UPDATED = "PROFILEUPDATED"; -} diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Services/ServerSideAuthTokenProvider.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Web/Services/ServerSideAuthTokenProvider.cs deleted file mode 100644 index 48fc618068..0000000000 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Services/ServerSideAuthTokenProvider.cs +++ /dev/null @@ -1,45 +0,0 @@ -#if BlazorServer -using System.Reflection; -#endif - - -namespace Bit.Websites.Careers.Web.Services; - -#if BlazorServer -public partial class ServerSideAuthTokenProvider : IAuthTokenProvider -{ - [AutoInject] private IJSRuntime _jsRuntime = default!; - [AutoInject] private IHttpContextAccessor _httpContextAccessor = default!; - - private static readonly PropertyInfo IsInitializedProp = Assembly.Load("Microsoft.AspNetCore.Components.Server")! - .GetType("Microsoft.AspNetCore.Components.Server.Circuits.RemoteJSRuntime")! - .GetProperty("IsInitialized")!; - - public async Task GetAccessTokenAsync() - { - var isInitialized = (bool)IsInitializedProp.GetValue(_jsRuntime)!; - - if (isInitialized) - { - return await _jsRuntime.InvokeAsync("App.getCookie", "access_token"); - } - - return _httpContextAccessor.HttpContext?.Request.Cookies["access_token"]; - } -} -#else -public class ServerSideAuthTokenProvider : IAuthTokenProvider -{ - private readonly IHttpContextAccessor _httpContextAccessor; - - public ServerSideAuthTokenProvider(IHttpContextAccessor httpContextAccessor) - { - _httpContextAccessor = httpContextAccessor; - } - - public Task GetAccessTokenAsync() - { - return Task.FromResult(_httpContextAccessor.HttpContext?.Request.Cookies["access_token"]); - } -} -#endif diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Shared/MainLayout.razor.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Web/Shared/MainLayout.razor.cs deleted file mode 100644 index 69f25b6957..0000000000 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Shared/MainLayout.razor.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Bit.Websites.Careers.Web.Shared; - -public partial class MainLayout -{ - -} diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Shared/MessageBox.razor.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Web/Shared/MessageBox.razor.cs deleted file mode 100644 index 661f938c01..0000000000 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Shared/MessageBox.razor.cs +++ /dev/null @@ -1,56 +0,0 @@ -namespace Bit.Websites.Careers.Web.Shared; - -public partial class MessageBox : IDisposable -{ - private static event Func OnShow = default!; - - private bool _isOpen; - private string _title = string.Empty; - private string _body = string.Empty; - - private static TaskCompletionSource? _tsc; - - public static async Task Show(string message, string title = "") - { - _tsc = new TaskCompletionSource(); - - await OnShow.Invoke(message, title); - - await _tsc.Task; - } - - protected override void OnInitialized() - { - OnShow += ShowMessageBox; - - base.OnInitialized(); - } - - private async Task ShowMessageBox(string message, string title) - { - await InvokeAsync(() => - { - _isOpen = true; - - _title = title; - _body = message; - - StateHasChanged(); - }); - } - - private void OnCloseClick() - { - _isOpen = false; - _tsc?.SetResult(null); - } - - - private void OnOkClick() - { - _isOpen = false; - _tsc?.SetResult(null); - } - - public void Dispose() => OnShow -= ShowMessageBox; -} diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Startup/Middlewares.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Web/Startup/Middlewares.cs deleted file mode 100644 index 15749f9397..0000000000 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Startup/Middlewares.cs +++ /dev/null @@ -1,33 +0,0 @@ -#if BlazorServer -namespace Bit.Websites.Careers.Web.Startup; - -public class Middlewares -{ - public static void Use(IApplicationBuilder app, IHostEnvironment env) - { - if (env.IsDevelopment()) - { - app.UseDeveloperExceptionPage(); - } - else - { - app.UseExceptionHandler("/Error"); - } - - if (env.IsDevelopment() is false) - { - app.UseHttpsRedirection(); - app.UseResponseCompression(); - } - app.UseStaticFiles(); - - app.UseRouting(); - - app.UseEndpoints(endpoints => - { - endpoints.MapBlazorHub(); - endpoints.MapFallbackToPage("/_Host"); - }); - } -} -#endif diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Startup/Services.cs b/src/Websites/Careers/src/Bit.Websites.Careers.Web/Startup/Services.cs deleted file mode 100644 index 8367c72099..0000000000 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Startup/Services.cs +++ /dev/null @@ -1,39 +0,0 @@ -#if BlazorServer -using System.IO.Compression; -using Microsoft.AspNetCore.ResponseCompression; - -namespace Bit.Websites.Careers.Web.Startup; - -public static class Services -{ - public static void Add(IServiceCollection services, IConfiguration configuration) - { - services.AddScoped(sp => - { - HttpClient httpClient = new(sp.GetRequiredService()) - { - BaseAddress = new Uri(sp.GetRequiredService().GetApiServerAddress()) - }; - - return httpClient; - }); - - services.AddHttpContextAccessor(); - services.AddRazorPages(); - services.AddServerSideBlazor(); - services.AddResponseCompression(opts => - { - opts.EnableForHttps = true; - opts.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(new[] { "application/octet-stream" }).ToArray(); - opts.Providers.Add(); - opts.Providers.Add(); - }) - .Configure(opt => opt.Level = CompressionLevel.Fastest) - .Configure(opt => opt.Level = CompressionLevel.Fastest); - services.AddTransient(); - - services.AddSharedServices(); - services.AddClientSharedServices(); - } -} -#endif diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Styles/abstracts/_mixins.scss b/src/Websites/Careers/src/Bit.Websites.Careers.Web/Styles/abstracts/_mixins.scss deleted file mode 100644 index 5f282702bb..0000000000 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Styles/abstracts/_mixins.scss +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/_Imports.razor b/src/Websites/Careers/src/Bit.Websites.Careers.Web/_Imports.razor deleted file mode 100644 index 60494d284a..0000000000 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Web/_Imports.razor +++ /dev/null @@ -1,20 +0,0 @@ -@using System.Reflection -@using System.Globalization -@using Microsoft.AspNetCore.Components -@using Microsoft.AspNetCore.Authorization -@using Microsoft.AspNetCore.Components.Web -@using Microsoft.AspNetCore.Components.Forms -@using Microsoft.AspNetCore.Components.Routing -@using Microsoft.AspNetCore.Components.Authorization -@using Microsoft.AspNetCore.Components.Web.Virtualization -@using Microsoft.Extensions.Configuration -@using Microsoft.JSInterop -@using Bit.BlazorUI -@using Bit.Websites.Careers -@using Bit.Websites.Careers.Web -@using Bit.Websites.Careers.Web.Shared -@using Bit.Websites.Careers.Web.Pages -@using Bit.Websites.Careers.Web.Components -@using Bit.Websites.Careers.Web.Services.Contracts -@using Bit.Websites.Careers.Web.Services -@using Bit.Websites.Careers.Shared \ No newline at end of file diff --git a/src/Websites/Careers/src/Directory.Build.props b/src/Websites/Careers/src/Directory.Build.props index 3bf5a64c85..d1fe7bcd44 100644 --- a/src/Websites/Careers/src/Directory.Build.props +++ b/src/Websites/Careers/src/Directory.Build.props @@ -1,39 +1,24 @@ - BlazorServer - - - DefaultDeploymentType - - - $(DefineConstants);BlazorWebAssembly - $(DefineConstants);BlazorServer - $(DefineConstants);DefaultDeploymentType - $(DefineConstants);SSR - $(DefineConstants);Static - - 11.0 enable enable - + true + $(NoWarn);CS1998;CS1591 + 12.0 en - - - - - + diff --git a/src/Websites/Platform/src/Bit.Websites.Platform.Client/Shared/PageOutlet.razor b/src/Websites/Platform/src/Bit.Websites.Platform.Client/Shared/PageOutlet.razor index ba8e7bbaef..bb59826cf7 100644 --- a/src/Websites/Platform/src/Bit.Websites.Platform.Client/Shared/PageOutlet.razor +++ b/src/Websites/Platform/src/Bit.Websites.Platform.Client/Shared/PageOutlet.razor @@ -14,11 +14,4 @@ - - -@code { - [Parameter] public string? Title { get; set; } - [Parameter] public string? Description { get; set; } - [Parameter] public string? Url { get; set; } - [Parameter] public string ImageUrl { get; set; } = "https://bitplatform.dev/images/og-image.svg"; -} \ No newline at end of file + \ No newline at end of file diff --git a/src/Websites/Platform/src/Bit.Websites.Platform.Client/Shared/PageOutlet.razor.cs b/src/Websites/Platform/src/Bit.Websites.Platform.Client/Shared/PageOutlet.razor.cs new file mode 100644 index 0000000000..f7a03b650f --- /dev/null +++ b/src/Websites/Platform/src/Bit.Websites.Platform.Client/Shared/PageOutlet.razor.cs @@ -0,0 +1,9 @@ + namespace Bit.Websites.Platform.Client.Shared; + +public partial class PageOutlet +{ + [Parameter] public string? Title { get; set; } + [Parameter] public string? Description { get; set; } + [Parameter] public string? Url { get; set; } + [Parameter] public string ImageUrl { get; set; } = "https://bitplatform.dev/images/og-image.svg"; +} diff --git a/src/Websites/Platform/src/Bit.Websites.Platform.Server/Components/App.razor b/src/Websites/Platform/src/Bit.Websites.Platform.Server/Components/App.razor index 8b14e29e3c..6feb33ca22 100644 --- a/src/Websites/Platform/src/Bit.Websites.Platform.Server/Components/App.razor +++ b/src/Websites/Platform/src/Bit.Websites.Platform.Server/Components/App.razor @@ -1,5 +1,4 @@ @using Bit.Websites.Platform.Client.Services -@attribute [StreamRendering(true)] @@ -64,9 +63,12 @@ - - - + @if (HttpContext.Request.IsCrawlerClient() is false) + { + + + + } diff --git a/src/Websites/Platform/src/Bit.Websites.Platform.Server/Components/App.razor.cs b/src/Websites/Platform/src/Bit.Websites.Platform.Server/Components/App.razor.cs new file mode 100644 index 0000000000..88728dabb4 --- /dev/null +++ b/src/Websites/Platform/src/Bit.Websites.Platform.Server/Components/App.razor.cs @@ -0,0 +1,23 @@ +using Microsoft.AspNetCore.Components; + +namespace Bit.Websites.Platform.Server.Components; + +[StreamRendering(enabled: true)] +public partial class App +{ + [CascadingParameter] HttpContext HttpContext { get; set; } = default!; + + protected override void OnInitialized() + { + HttpContext.Response.OnStarting(async _ => + { + HttpContext.Response.GetTypedHeaders().CacheControl = new() + { + MaxAge = TimeSpan.FromDays(7), + Public = true + }; + }, null!); + + base.OnInitialized(); + } +} diff --git a/src/Websites/Platform/src/Bit.Websites.Platform.Server/Extensions/HttpRequestExtensions.cs b/src/Websites/Platform/src/Bit.Websites.Platform.Server/Extensions/HttpRequestExtensions.cs index b8d735e228..12760a7e32 100644 --- a/src/Websites/Platform/src/Bit.Websites.Platform.Server/Extensions/HttpRequestExtensions.cs +++ b/src/Websites/Platform/src/Bit.Websites.Platform.Server/Extensions/HttpRequestExtensions.cs @@ -18,7 +18,7 @@ public static string GetBaseUrl(this HttpRequest req) return uriBuilder.Uri.AbsoluteUri; } - public static bool ShouldRenderStaticMode(this HttpRequest request) + public static bool IsCrawlerClient(this HttpRequest request) { var agent = GetLoweredUserAgent(request); diff --git a/src/Websites/Platform/src/Bit.Websites.Platform.Server/Services/NullAntiforgery.cs b/src/Websites/Platform/src/Bit.Websites.Platform.Server/Services/NullAntiforgery.cs new file mode 100644 index 0000000000..d351d8a31a --- /dev/null +++ b/src/Websites/Platform/src/Bit.Websites.Platform.Server/Services/NullAntiforgery.cs @@ -0,0 +1,22 @@ +using Microsoft.AspNetCore.Antiforgery; + +namespace Bit.Websites.Platform.Server.Services; + +public class NullAntiforgery : IAntiforgery +{ + private const string AntiforgeryTokenFieldName = "__RequestVerificationToken"; + private const string AntiforgeryTokenHeaderName = "RequestVerificationToken"; + + public AntiforgeryTokenSet GetAndStoreTokens(HttpContext httpContext) => new(string.Empty, string.Empty, AntiforgeryTokenFieldName, AntiforgeryTokenHeaderName); + + public AntiforgeryTokenSet GetTokens(HttpContext httpContext) => new(string.Empty, string.Empty, AntiforgeryTokenFieldName, AntiforgeryTokenHeaderName); + + public Task IsRequestValidAsync(HttpContext httpContext) => Task.FromResult(true); + + public void SetCookieTokenAndHeader(HttpContext httpContext) + { + return; + } + + public Task ValidateRequestAsync(HttpContext httpContext) => Task.FromResult(true); +} diff --git a/src/Websites/Platform/src/Bit.Websites.Platform.Server/Startup/Services.cs b/src/Websites/Platform/src/Bit.Websites.Platform.Server/Startup/Services.cs index 3e219ce741..06484865e8 100644 --- a/src/Websites/Platform/src/Bit.Websites.Platform.Server/Startup/Services.cs +++ b/src/Websites/Platform/src/Bit.Websites.Platform.Server/Startup/Services.cs @@ -2,6 +2,7 @@ using Microsoft.AspNetCore.HttpOverrides; using Microsoft.AspNetCore.ResponseCompression; using Bit.Websites.Platform.Server.Services; +using Microsoft.AspNetCore.Antiforgery; namespace Bit.Websites.Platform.Server.Startup; @@ -13,6 +14,7 @@ public static void Add(IServiceCollection services, IWebHostEnvironment env, ICo var appSettings = configuration.GetSection(nameof(AppSettings)).Get()!; + services.AddTransient(); services.AddHttpClient(); services.AddScoped(); diff --git a/src/Websites/Sales/.editorconfig b/src/Websites/Sales/.editorconfig new file mode 100644 index 0000000000..09b151e99d --- /dev/null +++ b/src/Websites/Sales/.editorconfig @@ -0,0 +1,124 @@ +# To learn more about .editorconfig see https://aka.ms/editorconfigdocs +############################### +# Core EditorConfig Options # +############################### +# All files +[*] +indent_style = space +indent_size = 4 +# Code files +[*.{cs,csx,vb,vbx}] +insert_final_newline = true +charset = utf-8-bom +############################### +# .NET Coding Conventions # +############################### +[*.{cs,vb}] +# Organize usings +dotnet_sort_system_directives_first = true +# this. preferences +dotnet_style_qualification_for_field = false:silent +dotnet_style_qualification_for_property = false:silent +dotnet_style_qualification_for_method = false:silent +dotnet_style_qualification_for_event = false:silent +# Language keywords vs BCL types preferences +dotnet_style_predefined_type_for_locals_parameters_members = true:silent +dotnet_style_predefined_type_for_member_access = true:silent +# Parentheses preferences +dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent +dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent +dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent +dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent +# Modifier preferences +dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent +dotnet_style_readonly_field = true:suggestion +# Expression-level preferences +dotnet_style_object_initializer = true:suggestion +dotnet_style_collection_initializer = true:suggestion +dotnet_style_explicit_tuple_names = true:suggestion +dotnet_style_null_propagation = true:suggestion +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:silent +dotnet_style_prefer_inferred_tuple_names = true:suggestion +dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion +dotnet_style_prefer_auto_properties = true:silent +dotnet_style_prefer_conditional_expression_over_assignment = true:silent +dotnet_style_prefer_conditional_expression_over_return = true:silent +############################### +# Naming Conventions # +############################### +# Style Definitions +dotnet_naming_style.pascal_case_style.capitalization = pascal_case +# Use PascalCase for constant fields +dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields +dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style +dotnet_naming_symbols.constant_fields.applicable_kinds = field +dotnet_naming_symbols.constant_fields.applicable_accessibilities = * +dotnet_naming_symbols.constant_fields.required_modifiers = const +############################### +# C# Coding Conventions # +############################### +[*.cs] +# var preferences +csharp_style_namespace_declarations = file_scoped:warning +csharp_style_var_for_built_in_types = true:silent +csharp_style_var_when_type_is_apparent = true:silent +csharp_style_var_elsewhere = true:silent +# Expression-bodied members +csharp_style_expression_bodied_methods = false:silent +csharp_style_expression_bodied_constructors = false:silent +csharp_style_expression_bodied_operators = false:silent +csharp_style_expression_bodied_properties = true:silent +csharp_style_expression_bodied_indexers = true:silent +csharp_style_expression_bodied_accessors = true:silent +# Pattern matching preferences +csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion +csharp_style_pattern_matching_over_as_with_null_check = true:suggestion +# Null-checking preferences +csharp_style_throw_expression = true:suggestion +csharp_style_conditional_delegate_call = true:suggestion +# Modifier preferences +csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion +# Expression-level preferences +csharp_prefer_braces = true:silent +csharp_style_deconstructed_variable_declaration = true:suggestion +csharp_prefer_simple_default_expression = true:suggestion +csharp_style_pattern_local_over_anonymous_function = true:suggestion +csharp_style_inlined_variable_declaration = true:suggestion +############################### +# C# Formatting Rules # +############################### +# New line preferences +csharp_new_line_before_open_brace = all +csharp_new_line_before_else = true +csharp_new_line_before_catch = true +csharp_new_line_before_finally = true +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_members_in_anonymous_types = true +csharp_new_line_between_query_expression_clauses = true +# Indentation preferences +csharp_indent_case_contents = true +csharp_indent_switch_labels = true +csharp_indent_labels = flush_left +# Space preferences +csharp_space_after_cast = false +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_between_method_declaration_parameter_list_parentheses = false +csharp_space_between_parentheses = false +csharp_space_before_colon_in_inheritance_clause = true +csharp_space_after_colon_in_inheritance_clause = true +csharp_space_around_binary_operators = before_and_after +csharp_space_between_method_declaration_empty_parameter_list_parentheses = false +csharp_space_between_method_call_name_and_opening_parenthesis = false +csharp_space_between_method_call_empty_parameter_list_parentheses = false +# Wrapping preferences +csharp_preserve_single_line_statements = true +csharp_preserve_single_line_blocks = true +############################### +# VB Coding Conventions # +############################### +[*.vb] +# Modifier preferences +visual_basic_preferred_modifier_order = Partial,Default,Private,Protected,Public,Friend,NotOverridable,Overridable,MustOverride,Overloads,Overrides,MustInherit,NotInheritable,Static,Shared,Shadows,ReadOnly,WriteOnly,Dim,Const,WithEvents,Widening,Narrowing,Custom,Async:suggestion diff --git a/src/Websites/Sales/.gitignore b/src/Websites/Sales/.gitignore index c36928d996..e5ed5e951d 100644 --- a/src/Websites/Sales/.gitignore +++ b/src/Websites/Sales/.gitignore @@ -213,6 +213,9 @@ ModelManifest.xml # VS Code .vscode +# .NET Meteor +.meteor + # Rider .idea @@ -222,6 +225,11 @@ profile.arm.json *.map *Resource.designer.cs /**/*.css +custom.aprof + +/src/Server/Api/Attachments/**/*.* + +/src/Bit.Websites.Sales.Client/Scripts/app*.js +/src/Bit.Websites.Sales.Client/wwwroot/scripts/app*.js -/src/Bit.Websites.Sales.Web/Scripts/app*.js -/src/Bit.Websites.Sales.Web/wwwroot/scripts/app*.js +/src/Bit.Websites.Sales.Server/Bit.Websites.SalesDb.db* \ No newline at end of file diff --git a/src/Websites/Sales/Bit.Websites.Sales.sln b/src/Websites/Sales/Bit.Websites.Sales.sln index 1d25b6f332..6bb3ab112a 100644 --- a/src/Websites/Sales/Bit.Websites.Sales.sln +++ b/src/Websites/Sales/Bit.Websites.Sales.sln @@ -1,19 +1,21 @@ + Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 -VisualStudioVersion = 17.0.31611.283 +VisualStudioVersion = 17.8.34302.71 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".SolutionItems", ".SolutionItems", "{5CF43F76-BB71-4B5B-B4DF-1C753E042A8F}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".SolutionItems", ".SolutionItems", "{07D3DE94-9EB8-41FE-8888-0A483D30EBFD}" ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig .gitignore = .gitignore + Clean.bat = Clean.bat src\Directory.Build.props = src\Directory.Build.props - README.md = README.md EndProjectSection EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bit.Websites.Sales.Api", "src\Bit.Websites.Sales.Api\Bit.Websites.Sales.Api.csproj", "{DD0474BE-082F-4BE2-92C6-BD454D0A0020}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bit.Websites.Sales.Shared", "src\Bit.Websites.Sales.Shared\Bit.Websites.Sales.Shared.csproj", "{7B577D88-492D-4B13-8B79-55BA13B51EE4}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bit.Websites.Sales.Shared", "src\Bit.Websites.Sales.Shared\Bit.Websites.Sales.Shared.csproj", "{2A240C93-0116-43D3-8409-E9167F655C7E}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bit.Websites.Sales.Server", "src\Bit.Websites.Sales.Server\Bit.Websites.Sales.Server.csproj", "{03920E8A-DB33-4239-BCD1-7EE3ECC6E19B}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bit.Websites.Sales.Web", "src\Bit.Websites.Sales.Web\Bit.Websites.Sales.Web.csproj", "{F41B194E-C7F8-42CD-ADCA-BEABBFD2AB2C}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bit.Websites.Sales.Client", "src\Bit.Websites.Sales.Client\Bit.Websites.Sales.Client.csproj", "{2B84944A-F323-4F0D-9D70-7FF99B0F7EA7}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -21,23 +23,23 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {DD0474BE-082F-4BE2-92C6-BD454D0A0020}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DD0474BE-082F-4BE2-92C6-BD454D0A0020}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DD0474BE-082F-4BE2-92C6-BD454D0A0020}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DD0474BE-082F-4BE2-92C6-BD454D0A0020}.Release|Any CPU.Build.0 = Release|Any CPU - {2A240C93-0116-43D3-8409-E9167F655C7E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {2A240C93-0116-43D3-8409-E9167F655C7E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {2A240C93-0116-43D3-8409-E9167F655C7E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {2A240C93-0116-43D3-8409-E9167F655C7E}.Release|Any CPU.Build.0 = Release|Any CPU - {F41B194E-C7F8-42CD-ADCA-BEABBFD2AB2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F41B194E-C7F8-42CD-ADCA-BEABBFD2AB2C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F41B194E-C7F8-42CD-ADCA-BEABBFD2AB2C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F41B194E-C7F8-42CD-ADCA-BEABBFD2AB2C}.Release|Any CPU.Build.0 = Release|Any CPU + {7B577D88-492D-4B13-8B79-55BA13B51EE4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7B577D88-492D-4B13-8B79-55BA13B51EE4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7B577D88-492D-4B13-8B79-55BA13B51EE4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7B577D88-492D-4B13-8B79-55BA13B51EE4}.Release|Any CPU.Build.0 = Release|Any CPU + {03920E8A-DB33-4239-BCD1-7EE3ECC6E19B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {03920E8A-DB33-4239-BCD1-7EE3ECC6E19B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {03920E8A-DB33-4239-BCD1-7EE3ECC6E19B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {03920E8A-DB33-4239-BCD1-7EE3ECC6E19B}.Release|Any CPU.Build.0 = Release|Any CPU + {2B84944A-F323-4F0D-9D70-7FF99B0F7EA7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2B84944A-F323-4F0D-9D70-7FF99B0F7EA7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2B84944A-F323-4F0D-9D70-7FF99B0F7EA7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2B84944A-F323-4F0D-9D70-7FF99B0F7EA7}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {61F7FB11-1E47-470C-91E2-47F8143E1572} + SolutionGuid = {62EABCA9-B5C9-489A-B101-38E38ACEDC1E} EndGlobalSection EndGlobal diff --git a/src/Websites/Sales/Clean.bat b/src/Websites/Sales/Clean.bat index ba7402ad9d..52aa2b50c5 100644 --- a/src/Websites/Sales/Clean.bat +++ b/src/Websites/Sales/Clean.bat @@ -1,16 +1,16 @@ -:: This batch script is designed for comprehensive cleaning of your project by deleting unnecessary files. -:: It's crucial to close any Integrated Development Environment (IDE), such as Visual Studio, etc., before executing this script to prevent any conflicts or loss of unsaved data. -:: Please note that the commands included in this script are specifically tailored for the Windows +:: This batch script cleans your project by deleting unnecessary files. +:: It is important to close any IDEs, such as Visual Studio, before running this script to prevent conflicts or data loss. +:: The commands in this script are specifically designed for Windows. -:: Delete css,js and source maps files if not tracked in git +:: Deletes CSS, JS, and source map files that are not tracked in Git. powershell -Command "[string]$trackedFiles = git ls-files; Get-ChildItem -Include *.css,*.min.css,*.js,*.min.js,*.map -Recurse | ForEach-Object { if ($trackedFiles -NotMatch $_.Name) { Remove-Item -Recurse -Path $_ -Confirm:$false -Force }}" -:: Runs dotnet clean for each csproj file +:: Runs the dotnet clean command for each .csproj file. powershell -Command "Get-ChildItem -Include *.csproj -Recurse | ForEach-Object { dotnet clean $_.FullName }" -:: Delete specified files & folders +:: Deletes the specified files and folders. powershell -Command "Get-ChildItem -Include *.csproj.user,Resources.designer.cs,bin,obj,node_modules,Packages,TestResults,AppPackages,.meteor -Recurse | ForEach-Object { Remove-Item -Recurse -Path $_ -Confirm:$false -Force }" FOR /d /r . %%d IN (.vs) DO @IF EXIST "%%d" rd /s /q "%%d" -:: Delete empty directories +:: Deletes empty directories. powershell -Command "Get-ChildItem -Recurse | Where-Object { $_.PSIsContainer -and @(Get-ChildItem -Lit $_.FullName).Count -eq 0 } | Remove-Item -Confirm:$false -Force" \ No newline at end of file diff --git a/src/Websites/Sales/Clean.sh b/src/Websites/Sales/Clean.sh index fe004842e6..04061b11a9 100644 --- a/src/Websites/Sales/Clean.sh +++ b/src/Websites/Sales/Clean.sh @@ -1,23 +1,23 @@ #!/bin/bash -# This batch script is designed for comprehensive cleaning of your project by deleting unnecessary files. -# It's crucial to close any Integrated Development Environment (IDE), such as vs code, etc., before executing this script to prevent any conflicts or loss of unsaved data. -# Please note that the commands included in this script are specifically tailored for the Linux/macOS +# This batch script cleans your project by deleting unnecessary files. +# It is important to close any IDEs, such as vs for mac, before running this script to prevent conflicts or data loss. +# The commands in this script are specifically designed for macOS/Linux. -# Runs dotnet clean for each csproj file +# Runs the dotnet clean command for each .csproj file. for csproj in $(find . -name '*.csproj'); do dotnet clean $csproj done -# Delete specified directories +# Deletes specified directories for dir in $(find . -type d \( -name "bin" -o -name "obj" -o -name "node_modules" -o -name "Packages" -o -name ".vs" -o -name "TestResults" -o -name "AppPackages" -o -name ".meteor" \)); do rm -rf $dir done -# Delete specified files +# Deletes specified files for file in $(find . -type f \( -name "*.csproj.user" -o -name "Resources.designer.cs" -o -name "*.css" -o -name "*.min.css" -o -name "*.js" -o -name "*.min.js" -o -name "*.map" \)); do rm -f $file done -# Delete empty directories +# Deletes empty directories. find . -type d -empty -delete \ No newline at end of file diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Api/Bit.Websites.Sales.Api.csproj b/src/Websites/Sales/src/Bit.Websites.Sales.Api/Bit.Websites.Sales.Api.csproj deleted file mode 100644 index 7fffb99357..0000000000 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Api/Bit.Websites.Sales.Api.csproj +++ /dev/null @@ -1,50 +0,0 @@ - - - net8.0 - - false - true - true - - - - - - - - - - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Api/Controllers/AppControllerBase.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Api/Controllers/AppControllerBase.cs deleted file mode 100644 index 4574dd94d9..0000000000 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Api/Controllers/AppControllerBase.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Bit.Websites.Sales.Api.Controllers; - -public partial class AppControllerBase : ControllerBase -{ - [AutoInject] protected AppSettings AppSettings = default!; - - [AutoInject] protected IStringLocalizer Localizer = default!; -} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Api/Extensions/IApplicationBuilderExtensions.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Api/Extensions/IApplicationBuilderExtensions.cs deleted file mode 100644 index ba15fd4cc2..0000000000 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Api/Extensions/IApplicationBuilderExtensions.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Bit.Websites.Sales.Api.Middlewares; - -namespace Microsoft.AspNetCore.Builder; - -public static class IApplicationBuilderExtensions -{ - public static IApplicationBuilder UseHttpResponseExceptionHandler(this IApplicationBuilder builder) - { - return builder.UseMiddleware(); - } -} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Api/Extensions/IServiceCollectionExtensions.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Api/Extensions/IServiceCollectionExtensions.cs deleted file mode 100644 index c43e8e64e6..0000000000 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Api/Extensions/IServiceCollectionExtensions.cs +++ /dev/null @@ -1,35 +0,0 @@ -using Swashbuckle.AspNetCore.SwaggerGen; -using Bit.Websites.Sales.Api; - -namespace Microsoft.Extensions.DependencyInjection; - -public static class IServiceCollectionExtensions -{ - public static void AddSwaggerGen(this IServiceCollection services) - { - services.AddSwaggerGen(options => - { - options.OperationFilter(); - }); - } - - public static void AddHealthChecks(this IServiceCollection services, IWebHostEnvironment env, IConfiguration configuration) - { - var appSettings = configuration.GetSection(nameof(AppSettings)).Get(); - - var healthCheckSettings = appSettings.HealthCheckSettings; - - if (healthCheckSettings.EnableHealthChecks is false) - return; - - services.AddHealthChecksUI(setupSettings: setup => - { - setup.AddHealthCheckEndpoint("TodoHealthChecks", env.IsDevelopment() ? "https://localhost:5021/healthz" : "/healthz"); - }).AddInMemoryStorage(); - - var healthChecksBuilder = services.AddHealthChecks() - .AddProcessAllocatedMemoryHealthCheck(maximumMegabytesAllocated: 6 * 1024) - .AddDiskStorageHealthCheck(opt => - opt.AddDrive(Path.GetPathRoot(Directory.GetCurrentDirectory()), minimumFreeMegabytes: 5 * 1024)); - } -} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Api/Extensions/ODataOperationFilter.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Api/Extensions/ODataOperationFilter.cs deleted file mode 100644 index e575ce9314..0000000000 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Api/Extensions/ODataOperationFilter.cs +++ /dev/null @@ -1,111 +0,0 @@ -using Microsoft.AspNetCore.Mvc.Controllers; -using Microsoft.OpenApi.Models; - -namespace Swashbuckle.AspNetCore.SwaggerGen; - -/// -/// https://docs.microsoft.com/en-us/odata/concepts/queryoptions-overview -/// -public class ODataOperationFilter : IOperationFilter -{ - public void Apply(OpenApiOperation operation, OperationFilterContext context) - { - if (operation.Parameters == null) operation.Parameters = new List(); - - var descriptor = context.ApiDescription.ActionDescriptor as ControllerActionDescriptor; - - var odataQueryOptionsParameter = descriptor.Parameters.SingleOrDefault(p => typeof(ODataQueryOptions).IsAssignableFrom(p.ParameterType)); - - if (descriptor != null && descriptor.FilterDescriptors.Any(filter => filter.Filter is EnableQueryAttribute) || odataQueryOptionsParameter is not null) - { - operation.Parameters.Add(new OpenApiParameter() - { - Name = "$select", - In = ParameterLocation.Query, - Schema = new OpenApiSchema - { - Type = "string", - }, - Description = "Returns only the selected properties. (ex. FirstName, LastName)", - Required = false - }); - - operation.Parameters.Add(new OpenApiParameter() - { - Name = "$expand", - In = ParameterLocation.Query, - Schema = new OpenApiSchema - { - Type = "string", - }, - Description = "Include only the selected objects. (ex. Childrens, Locations)", - Required = false - }); - - operation.Parameters.Add(new OpenApiParameter() - { - Name = "$filter", - In = ParameterLocation.Query, - Schema = new OpenApiSchema - { - Type = "string", - }, - Description = "Filter the response with OData filter queries.", - Required = false - }); - - operation.Parameters.Add(new OpenApiParameter() - { - Name = "$search", - In = ParameterLocation.Query, - Schema = new OpenApiSchema - { - Type = "string", - }, - Description = "Filter the response with OData search queries.", - Required = false - }); - - operation.Parameters.Add(new OpenApiParameter() - { - Name = "$top", - In = ParameterLocation.Query, - Schema = new OpenApiSchema - { - Type = "int", - }, - Description = "Number of objects to return. (ex. 25)", - Required = false - }); - - operation.Parameters.Add(new OpenApiParameter() - { - Name = "$skip", - In = ParameterLocation.Query, - Schema = new OpenApiSchema - { - Type = "int", - }, - Description = "Number of objects to skip in the current order (ex. 50)", - Required = false - }); - - operation.Parameters.Add(new OpenApiParameter() - { - Name = "$orderby", - In = ParameterLocation.Query, - Schema = new OpenApiSchema - { - Type = "string", - }, - Description = "Define the order by one or more fields (ex. LastModified)", - Required = false - }); - } - - if (odataQueryOptionsParameter is not null) - { - operation.Parameters.Remove(operation.Parameters.Single(p => p.Name == odataQueryOptionsParameter.Name)); - } - } -} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Api/Middlewares/HttpResponseExceptionHandlerMiddleware.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Api/Middlewares/HttpResponseExceptionHandlerMiddleware.cs deleted file mode 100644 index f1514d5ae1..0000000000 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Api/Middlewares/HttpResponseExceptionHandlerMiddleware.cs +++ /dev/null @@ -1,65 +0,0 @@ -using System.Net; -using System.Reflection; - -namespace Bit.Websites.Sales.Api.Middlewares; - -public class HttpResponseExceptionHandlerMiddleware -{ - private readonly RequestDelegate _next; - - public HttpResponseExceptionHandlerMiddleware(RequestDelegate next) - { - _next = next; - } - - public async Task Invoke(HttpContext context, IHostEnvironment webHostEnvironment) - { - // Using the Request-Id header, one can find the log for server-related exceptions - context.Response.Headers.Append("Request-ID", context.TraceIdentifier); - - try - { - await _next(context); - } - catch (Exception e) - { - var exception = UnWrapException(e); - var localizer = context.RequestServices.GetRequiredService>(); - var knownException = exception as KnownException; - - // The details of all of the exceptions are returned only in dev mode. in any other modes like production, only the details of the known exceptions are returned. - string key = knownException?.Key ?? nameof(UnknownException); - string message = knownException?.Message ?? (webHostEnvironment.IsDevelopment() ? exception.Message : localizer[nameof(UnknownException)]); - - var statusCode = (int)(exception is RestException restExp ? restExp.StatusCode : HttpStatusCode.InternalServerError); - - if (exception is KnownException && message == key) - { - message = localizer[message]; - } - - RestErrorInfo restExceptionPayload = new RestErrorInfo - { - Key = key, - Message = message, - ExceptionType = knownException?.GetType().FullName ?? typeof(UnknownException).FullName - }; - - if (exception is ResourceValidationException validationException) - { - restExceptionPayload.Payload = validationException.Payload; - } - - context.Response.StatusCode = statusCode; - - await context.Response.WriteAsJsonAsync(restExceptionPayload); - } - } - - private Exception UnWrapException(Exception exp) - { - return (exp is TargetInvocationException && exp.InnerException is not null) - ? exp.InnerException - : exp; - } -} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Api/Models/Emailing/NewContactUsSubmitModel.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Api/Models/Emailing/NewContactUsSubmitModel.cs deleted file mode 100644 index 1b95b52503..0000000000 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Api/Models/Emailing/NewContactUsSubmitModel.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Bit.Websites.Sales.Shared.Dtos.ContactUs; - -namespace Bit.Websites.Sales.Api.Models.Emailing; - -public class NewContactUsSubmitModel -{ - public ContactUsDto ContactUsInfo { get; set; } - - public Uri? HostUri { get; set; } -} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Api/Program.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Api/Program.cs deleted file mode 100644 index 1dda232810..0000000000 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Api/Program.cs +++ /dev/null @@ -1,13 +0,0 @@ -var builder = WebApplication.CreateBuilder(args); - -#if BlazorWebAssembly -builder.Configuration.AddClientConfigurations(); -#endif - -Bit.Websites.Sales.Api.Startup.Services.Add(builder.Services, builder.Environment, builder.Configuration); - -var app = builder.Build(); - -Bit.Websites.Sales.Api.Startup.Middlewares.Use(app, builder.Environment, builder.Configuration); - -app.Run(); diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Api/Startup/Middlewares.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Api/Startup/Middlewares.cs deleted file mode 100644 index f60231a563..0000000000 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Api/Startup/Middlewares.cs +++ /dev/null @@ -1,93 +0,0 @@ -using HealthChecks.UI.Client; -using Microsoft.AspNetCore.Diagnostics.HealthChecks; -using Microsoft.Net.Http.Headers; - -namespace Bit.Websites.Sales.Api.Startup; - -public class Middlewares -{ - public static void Use(IApplicationBuilder app, IHostEnvironment env, IConfiguration configuration) - { - app.UseForwardedHeaders(); - - if (env.IsDevelopment()) - { - app.UseDeveloperExceptionPage(); - -#if BlazorWebAssembly - if (env.IsDevelopment()) - { - app.UseWebAssemblyDebugging(); - } -#endif - } - -#if BlazorWebAssembly - app.UseBlazorFrameworkFiles(); -#endif - - if (env.IsDevelopment() is false) - { - app.UseHttpsRedirection(); - app.UseResponseCompression(); - } - - app.UseStaticFiles(new StaticFileOptions - { - OnPrepareResponse = ctx => - { - // https://bitplatform.dev/templates/cache-mechanism - ctx.Context.Response.GetTypedHeaders().CacheControl = new CacheControlHeaderValue() - { - MaxAge = TimeSpan.FromDays(7), - Public = true - }; - } - }); - - app.UseRouting(); - - app.UseCors(options => options.WithOrigins("https://localhost:4021").AllowAnyHeader().AllowAnyMethod().AllowCredentials()); - - app.UseResponseCaching(); - -#if MultilingualEnabled - var supportedCultures = CultureInfoManager.SupportedCultures.Select(sc => CultureInfoManager.CreateCultureInfo(sc.code)).ToArray(); - app.UseRequestLocalization(new RequestLocalizationOptions - { - SupportedCultures = supportedCultures, - SupportedUICultures = supportedCultures, - ApplyCurrentCultureToResponseHeaders = true - }.SetDefaultCulture(CultureInfoManager.DefaultCulture.code)); -#endif - - app.UseHttpResponseExceptionHandler(); - - app.UseSwagger(); - - app.UseSwaggerUI(); - - app.UseEndpoints(endpoints => - { - endpoints.MapControllers(); - - var appSettings = configuration.GetSection(nameof(AppSettings)).Get(); - - var healthCheckSettings = appSettings.HealthCheckSettings; - - if (healthCheckSettings.EnableHealthChecks) - { - endpoints.MapHealthChecks("/healthz", new HealthCheckOptions - { - ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse - }); - - endpoints.MapHealthChecksUI(); - } - -#if BlazorWebAssembly - endpoints.MapFallbackToPage("/_Host"); -#endif - }); - } -} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Api/Startup/Services.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Api/Startup/Services.cs deleted file mode 100644 index b9426c506e..0000000000 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Api/Startup/Services.cs +++ /dev/null @@ -1,97 +0,0 @@ -using System.IO.Compression; -using Microsoft.AspNetCore.HttpOverrides; -using Microsoft.AspNetCore.OData; -using Microsoft.AspNetCore.ResponseCompression; -using Bit.Websites.Sales.Api.Services; -#if BlazorWebAssembly -using Microsoft.AspNetCore.Components; -using Bit.Websites.Sales.Web.Services; -#endif - -namespace Bit.Websites.Sales.Api.Startup; - -public static class Services -{ - public static void Add(IServiceCollection services, IWebHostEnvironment env, IConfiguration configuration) - { - // Services being registered here can get injected into controllers and services in Api project. - - var appSettings = configuration.GetSection(nameof(AppSettings)).Get(); - - services.AddSharedServices(); - -#if BlazorWebAssembly - services.AddClientSharedServices(); - - // In the Pre-Rendering mode, the configured HttpClient will use the access_token provided by the cookie in the request, so the pre-rendered content would be fitting for the current user. - services.AddHttpClient("WebAssemblyPreRenderingHttpClient") - .ConfigurePrimaryHttpMessageHandler() - .ConfigureHttpClient((sp, httpClient) => - { - Uri.TryCreate(configuration.GetApiServerAddress(), UriKind.RelativeOrAbsolute, out var apiServerAddress); - if (apiServerAddress!.IsAbsoluteUri is false) - { - apiServerAddress = new Uri($"{sp.GetRequiredService().HttpContext!.Request.GetBaseUrl()}{apiServerAddress}"); - } - httpClient.BaseAddress = apiServerAddress; - }); - services.AddScoped(); - - services.AddScoped(sp => - { - IHttpClientFactory httpClientFactory = sp.GetRequiredService(); - return httpClientFactory.CreateClient("WebAssemblyPreRenderingHttpClient"); - // this is for pre rendering of blazor webassembly - // for other usages of httpclient, for example calling 3rd party apis, either use services.AddHttpClient("NamedHttpClient") or services.AddHttpClient(); - }); - services.AddRazorPages(); -#endif - services.AddHttpClient(); - services.AddScoped(); - services.AddCors(); - - services - .AddControllers() - .AddOData(options => options.EnableQueryFeatures()) - .AddDataAnnotationsLocalization(options => options.DataAnnotationLocalizerProvider = StringLocalizerProvider.ProvideLocalizer) - .ConfigureApiBehaviorOptions(options => - { - options.InvalidModelStateResponseFactory = context => - { - throw new ResourceValidationException(context.ModelState.Select(ms => (ms.Key, ms.Value!.Errors.Select(e => new LocalizedString(e.ErrorMessage, e.ErrorMessage)).ToArray())).ToArray()); - }; - }); - - services.Configure(options => - { - options.ForwardedHeaders = ForwardedHeaders.All; - options.ForwardedHostHeaderName = "X-Host"; - }); - - services.AddResponseCaching(); - - services.AddHttpContextAccessor(); - - services.AddResponseCompression(opts => - { - opts.EnableForHttps = true; - opts.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(new[] { "application/octet-stream" }).ToArray(); - opts.Providers.Add(); - opts.Providers.Add(); - }) - .Configure(opt => opt.Level = CompressionLevel.Fastest) - .Configure(opt => opt.Level = CompressionLevel.Fastest); - - services.Configure(configuration.GetSection(nameof(AppSettings))); - - services.AddScoped(sp => sp.GetRequiredService>().Value); - - services.AddEndpointsApiExplorer(); - - services.AddAutoMapper(typeof(Program).Assembly); - - services.AddSwaggerGen(); - - services.AddHealthChecks(env, configuration); - } -} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Api/appsettings.Development.json b/src/Websites/Sales/src/Bit.Websites.Sales.Api/appsettings.Development.json deleted file mode 100644 index 3d61a0466b..0000000000 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Api/appsettings.Development.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "AppSettings": { - "WebServerAddress": "https://localhost:4021/" - } -} \ No newline at end of file diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Bit.Websites.Sales.Web.csproj b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Bit.Websites.Sales.Client.csproj similarity index 63% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/Bit.Websites.Sales.Web.csproj rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/Bit.Websites.Sales.Client.csproj index bf41f8e141..26b6f38d03 100644 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Bit.Websites.Sales.Web.csproj +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Bit.Websites.Sales.Client.csproj @@ -1,13 +1,12 @@ - + + net8.0 - enable enable - - true - false - true - true + enable + true + Default + true false @@ -17,10 +16,7 @@ - - - - + @@ -33,8 +29,6 @@ - - all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -43,8 +37,6 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - - @@ -52,10 +44,10 @@ - - - - + + + + @@ -78,7 +70,7 @@ - + diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Components/Case.razor b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Components/Case.razor similarity index 95% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/Components/Case.razor rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/Components/Case.razor index 2d783d55ee..c30f1c6041 100644 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Components/Case.razor +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Components/Case.razor @@ -32,5 +32,5 @@ @code { [Parameter] - public Bit.Websites.Sales.Web.Models.Case ShowCase { get; set; } + public Bit.Websites.Sales.Client.Models.Case ShowCase { get; set; } } \ No newline at end of file diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Components/Case.razor.scss b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Components/Case.razor.scss similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/Components/Case.razor.scss rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/Components/Case.razor.scss diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Components/PageOutlet.razor b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Components/PageOutlet.razor similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/Components/PageOutlet.razor rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/Components/PageOutlet.razor diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Components/ProcessAccordion.razor b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Components/ProcessAccordion.razor similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/Components/ProcessAccordion.razor rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/Components/ProcessAccordion.razor diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Components/ProcessAccordion.razor.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Components/ProcessAccordion.razor.cs similarity index 75% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/Components/ProcessAccordion.razor.cs rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/Components/ProcessAccordion.razor.cs index 7bbbbd1509..16628701b4 100644 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Components/ProcessAccordion.razor.cs +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Components/ProcessAccordion.razor.cs @@ -1,4 +1,4 @@ -namespace Bit.Websites.Sales.Web.Components; +namespace Bit.Websites.Sales.Client.Components; public partial class ProcessAccordion { diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Components/ProcessAccordion.razor.scss b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Components/ProcessAccordion.razor.scss similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/Components/ProcessAccordion.razor.scss rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/Components/ProcessAccordion.razor.scss diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Extensions/IConfigurationBuilderExtensions.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Extensions/IConfigurationBuilderExtensions.cs similarity index 71% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/Extensions/IConfigurationBuilderExtensions.cs rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/Extensions/IConfigurationBuilderExtensions.cs index ad04cef8df..1c61dbbe26 100644 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Extensions/IConfigurationBuilderExtensions.cs +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Extensions/IConfigurationBuilderExtensions.cs @@ -6,7 +6,7 @@ public static class IConfigurationBuilderExtensions { public static void AddClientConfigurations(this IConfigurationBuilder builder) { - var assembly = Assembly.Load("Bit.Websites.Sales.Web"); - builder.AddJsonStream(assembly.GetManifestResourceStream("Bit.Websites.Sales.Web.appsettings.json")!); + var assembly = Assembly.Load("Bit.Websites.Sales.Client"); + builder.AddJsonStream(assembly.GetManifestResourceStream("Bit.Websites.Sales.Client.appsettings.json")!); } } diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Client/Extensions/IConfigurationExtensions.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Extensions/IConfigurationExtensions.cs new file mode 100644 index 0000000000..4bb315c1db --- /dev/null +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Extensions/IConfigurationExtensions.cs @@ -0,0 +1,10 @@ +namespace Microsoft.Extensions.Configuration; +public static class IConfigurationExtensions +{ + public static string GetApiServerAddress(this IConfiguration configuration) + { + var apiServerAddress = configuration.GetValue("ApiServerAddress", defaultValue: "api/")!; + + return Uri.TryCreate(apiServerAddress, UriKind.RelativeOrAbsolute, out _) ? apiServerAddress : throw new InvalidOperationException($"Api server address {apiServerAddress} is invalid"); + } +} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Client/Extensions/IListExtensions.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Extensions/IListExtensions.cs new file mode 100644 index 0000000000..8f50eb4679 --- /dev/null +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Extensions/IListExtensions.cs @@ -0,0 +1,23 @@ +namespace System.Collections.Generic; + +public static class IListExtensions +{ + // Basically a Polyfill since we now expose IList instead of List + // which is better but IList doesn't have AddRange + public static void AddRange(this IList list, IEnumerable items) + { + ArgumentNullException.ThrowIfNull(list); + ArgumentNullException.ThrowIfNull(items); + + if (list is List asList) + { + asList.AddRange(items); + return; + } + + foreach (T item in items) + { + list.Add(item); + } + } +} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Client/Extensions/IServiceCollectionExtensions.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Extensions/IServiceCollectionExtensions.cs new file mode 100644 index 0000000000..7eec73e901 --- /dev/null +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Extensions/IServiceCollectionExtensions.cs @@ -0,0 +1,24 @@ +using Bit.Websites.Sales.Client.Services.HttpMessageHandlers; + +namespace Microsoft.Extensions.DependencyInjection; + +public static class IServiceCollectionExtensions +{ + public static IServiceCollection AddClientSharedServices(this IServiceCollection services) + { + services.AddSharedServices(); + + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddBitBlazorUIServices(); + + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + + services.AddScoped(); + + return services; + } +} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Client/Extensions/JsRuntimeExtension.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Extensions/JsRuntimeExtension.cs new file mode 100644 index 0000000000..ba3ef05735 --- /dev/null +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Extensions/JsRuntimeExtension.cs @@ -0,0 +1,19 @@ +namespace Microsoft.JSInterop; + +public static class JSRuntimeExtension +{ + public static async Task ToggleBodyOverflow(this IJSRuntime jsRuntime, bool isNavOpen) + { + await jsRuntime.InvokeVoidAsync("toggleBodyOverflow", isNavOpen); + } + + public static async Task GoBack(this IJSRuntime jsRuntime) + { + await jsRuntime.InvokeVoidAsync("App.goBack"); + } + + public static async Task ApplyBodyElementClasses(this IJSRuntime jsRuntime, List cssClasses, Dictionary cssVariables) + { + await jsRuntime.InvokeVoidAsync("App.applyBodyElementClasses", cssClasses, cssVariables); + } +} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Models/Case.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Models/Case.cs similarity index 92% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/Models/Case.cs rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/Models/Case.cs index 4e32981dcf..695aa74e34 100644 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Models/Case.cs +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Models/Case.cs @@ -1,4 +1,4 @@ -namespace Bit.Websites.Sales.Web.Models; +namespace Bit.Websites.Sales.Client.Models; public class Case { diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Models/CaseFeature.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Models/CaseFeature.cs similarity index 76% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/Models/CaseFeature.cs rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/Models/CaseFeature.cs index 82b23b0563..a8a4bf4027 100644 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Models/CaseFeature.cs +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Models/CaseFeature.cs @@ -1,4 +1,4 @@ -namespace Bit.Websites.Sales.Web.Models; +namespace Bit.Websites.Sales.Client.Models; public class CaseFeature { diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Pages/AboutPage.razor b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Pages/AboutPage.razor similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/Pages/AboutPage.razor rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/Pages/AboutPage.razor diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Pages/AboutPage.razor.scss b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Pages/AboutPage.razor.scss similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/Pages/AboutPage.razor.scss rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/Pages/AboutPage.razor.scss diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Pages/CasesPage.razor b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Pages/CasesPage.razor similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/Pages/CasesPage.razor rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/Pages/CasesPage.razor diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Client/Pages/CasesPage.razor.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Pages/CasesPage.razor.cs new file mode 100644 index 0000000000..286232cfe1 --- /dev/null +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Pages/CasesPage.razor.cs @@ -0,0 +1,5 @@ +namespace Bit.Websites.Sales.Client.Pages; + +public partial class ShowCasePage +{ +} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Pages/CasesPage.razor.scss b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Pages/CasesPage.razor.scss similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/Pages/CasesPage.razor.scss rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/Pages/CasesPage.razor.scss diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Pages/HomePage.razor b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Pages/HomePage.razor similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/Pages/HomePage.razor rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/Pages/HomePage.razor diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Pages/HomePage.razor.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Pages/HomePage.razor.cs similarity index 61% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/Pages/HomePage.razor.cs rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/Pages/HomePage.razor.cs index ee2156c895..b98f7845a6 100644 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Pages/HomePage.razor.cs +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Pages/HomePage.razor.cs @@ -1,4 +1,4 @@ -namespace Bit.Websites.Sales.Web.Pages; +namespace Bit.Websites.Sales.Client.Pages; public partial class HomePage { diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Pages/HomePage.razor.scss b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Pages/HomePage.razor.scss similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/Pages/HomePage.razor.scss rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/Pages/HomePage.razor.scss diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Pages/ServicesPage.razor b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Pages/ServicesPage.razor similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/Pages/ServicesPage.razor rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/Pages/ServicesPage.razor diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Pages/ServicesPage.razor.scss b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Pages/ServicesPage.razor.scss similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/Pages/ServicesPage.razor.scss rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/Pages/ServicesPage.razor.scss diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Pages/ShowCaseDetailPage.razor b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Pages/ShowCaseDetailPage.razor similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/Pages/ShowCaseDetailPage.razor rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/Pages/ShowCaseDetailPage.razor diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Pages/ShowCaseDetailPage.razor.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Pages/ShowCaseDetailPage.razor.cs similarity index 78% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/Pages/ShowCaseDetailPage.razor.cs rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/Pages/ShowCaseDetailPage.razor.cs index 68cd0bfcc4..e964615850 100644 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Pages/ShowCaseDetailPage.razor.cs +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Pages/ShowCaseDetailPage.razor.cs @@ -1,7 +1,7 @@ using System.Reflection; -using Case = Bit.Websites.Sales.Web.Models.Case; +using Case = Bit.Websites.Sales.Client.Models.Case; -namespace Bit.Websites.Sales.Web.Pages; +namespace Bit.Websites.Sales.Client.Pages; public partial class ShowCaseDetailPage { @@ -12,7 +12,7 @@ public partial class ShowCaseDetailPage protected override async Task OnInitAsync() { var cases = new List(); - cases = await System.Text.Json.JsonSerializer.DeserializeAsync>(Assembly.Load("Bit.Websites.Sales.Web")!.GetManifestResourceStream("Bit.Websites.Sales.Web.Data.Cases.json")!); + cases = await System.Text.Json.JsonSerializer.DeserializeAsync>(Assembly.Load("Bit.Websites.Sales.Client")!.GetManifestResourceStream("Bit.Websites.Sales.Client.Data.Cases.json")!); ShowCase = cases?.Find(item => item.Key == CaseKey); await base.OnInitAsync(); } diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Pages/ShowCaseDetailPage.razor.scss b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Pages/ShowCaseDetailPage.razor.scss similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/Pages/ShowCaseDetailPage.razor.scss rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/Pages/ShowCaseDetailPage.razor.scss diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Pages/YourTeamPage.razor b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Pages/YourTeamPage.razor similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/Pages/YourTeamPage.razor rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/Pages/YourTeamPage.razor diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Pages/YourTeamPage.razor.scss b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Pages/YourTeamPage.razor.scss similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/Pages/YourTeamPage.razor.scss rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/Pages/YourTeamPage.razor.scss diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Client/Program.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Program.cs new file mode 100644 index 0000000000..bbc82b2474 --- /dev/null +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Program.cs @@ -0,0 +1,22 @@ +using Bit.Websites.Sales.Client.Services.HttpMessageHandlers; +using Microsoft.AspNetCore.Components.WebAssembly.Hosting; + +var builder = WebAssemblyHostBuilder.CreateDefault(args); + +builder.Configuration.AddClientConfigurations(); + +Uri.TryCreate(builder.Configuration.GetApiServerAddress(), UriKind.RelativeOrAbsolute, out var apiServerAddress); + +if (apiServerAddress!.IsAbsoluteUri is false) +{ + apiServerAddress = new Uri($"{builder.HostEnvironment.BaseAddress}{apiServerAddress}"); +} + +builder.Services.AddSingleton(sp => new HttpClient(sp.GetRequiredService()) { BaseAddress = apiServerAddress }); +builder.Services.AddScoped(); + +builder.Services.AddClientSharedServices(); + +var host = builder.Build(); + +await host.RunAsync(); diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Client/Routes.razor b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Routes.razor new file mode 100644 index 0000000000..870dd6af21 --- /dev/null +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Routes.razor @@ -0,0 +1,14 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Client/Routes.razor.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Routes.razor.cs new file mode 100644 index 0000000000..12d1d5b477 --- /dev/null +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Routes.razor.cs @@ -0,0 +1,21 @@ +using Microsoft.AspNetCore.Components.Routing; + +namespace Bit.Websites.Sales.Client; + +public partial class Routes +{ + private List _lazyLoadedAssemblies = []; + [AutoInject] private Microsoft.AspNetCore.Components.WebAssembly.Services.LazyAssemblyLoader _assemblyLoader = default!; + + private async Task OnNavigateAsync(NavigationContext args) + { + if (OperatingSystem.IsBrowser()) + { + if ((args.Path is "dashboard") && _lazyLoadedAssemblies.Any(asm => asm.GetName().Name == "Newtonsoft.Json") is false) + { + var assemblies = await _assemblyLoader.LoadAssembliesAsync(["Newtonsoft.Json.wasm", "System.Private.Xml.wasm", "System.Data.Common.wasm"]); + _lazyLoadedAssemblies.AddRange(assemblies); + } + } + } +} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Scripts/app.ts b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Scripts/app.ts similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/Scripts/app.ts rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/Scripts/app.ts diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Services/Contracts/IExceptionHandler.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Services/Contracts/IExceptionHandler.cs similarity index 68% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/Services/Contracts/IExceptionHandler.cs rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/Services/Contracts/IExceptionHandler.cs index 295b8f3aa4..8d59668b79 100644 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Services/Contracts/IExceptionHandler.cs +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Services/Contracts/IExceptionHandler.cs @@ -1,4 +1,4 @@ -namespace Bit.Websites.Sales.Web.Services.Contracts; +namespace Bit.Websites.Sales.Client.Services.Contracts; public interface IExceptionHandler { diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Client/Services/Contracts/IPrerenderStateService.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Services/Contracts/IPrerenderStateService.cs new file mode 100644 index 0000000000..ebe24891c7 --- /dev/null +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Services/Contracts/IPrerenderStateService.cs @@ -0,0 +1,17 @@ +namespace Bit.Websites.Sales.Client.Services.Contracts; + +/// +/// This service simplifies the process of persisting application state in Pre-Rendering mode +/// (explained in this documentation: https://docs.microsoft.com/en-us/aspnet/core/blazor/components/prerendering-and-integration#persist-prerendered-state). +/// If your project does not require prerendering to be enabled, you can completely remove this service and its usages from your project. +/// +public interface IPrerenderStateService +{ + /// + /// Instead of using ApplicationState.TryTakeFromJson, ApplicationState.RegisterOnPersisting, + /// and ApplicationState.PersistAsJson (explained here: https://docs.microsoft.com/en-us/aspnet/core/blazor/components/prerendering-and-integration#persist-prerendered-state), + /// one can easily use the following method () in the OnInit lifecycle method of the Blazor components or pages + /// to retrieve everything that requires an async-await (like current user's info). + /// + Task GetValue(string key, Func> factory); +} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Client/Services/Contracts/IPubSubService.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Services/Contracts/IPubSubService.cs new file mode 100644 index 0000000000..2fcbba92dd --- /dev/null +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Services/Contracts/IPubSubService.cs @@ -0,0 +1,10 @@ +namespace Bit.Websites.Sales.Client.Services.Contracts; + +/// +/// Contract for Publish/Subscribe pattern. +/// +public interface IPubSubService +{ + void Publish(string message, object? payload); + Action Subscribe(string message, Action handler); +} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Client/Services/ExceptionHandler.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Services/ExceptionHandler.cs new file mode 100644 index 0000000000..7a4bdf2d80 --- /dev/null +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Services/ExceptionHandler.cs @@ -0,0 +1,27 @@ +using System.Diagnostics; + +namespace Bit.Websites.Sales.Client.Services; + +public partial class ExceptionHandler : IExceptionHandler +{ + [AutoInject] MessageBoxService _messageBoxService = default!; + + public void Handle(Exception exception, IDictionary? parameters = null) + { +#if DEBUG + string exceptionMessage = (exception as KnownException)?.Message ?? exception.ToString(); + _ = _messageBoxService.Show(exceptionMessage, "Error"); + _ = Console.Out.WriteLineAsync(exceptionMessage); + Debugger.Break(); +#else + if (exception is KnownException knownException) + { + _ = _messageBoxService.Show(knownException.Message, "Error"); + } + else + { + _ = _messageBoxService.Show("Unknown error", "Error"); + } +#endif + } +} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Client/Services/HttpMessageHandlers/ExceptionDelegatingHandler.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Services/HttpMessageHandlers/ExceptionDelegatingHandler.cs new file mode 100644 index 0000000000..7c880fa49e --- /dev/null +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Services/HttpMessageHandlers/ExceptionDelegatingHandler.cs @@ -0,0 +1,60 @@ +using System.Net; + +namespace Bit.Websites.Sales.Client.Services.HttpMessageHandlers; + +public class ExceptionDelegatingHandler + : DelegatingHandler +{ + public ExceptionDelegatingHandler(HttpClientHandler httpClientHandler) + : base(httpClientHandler) + { + + } + + public ExceptionDelegatingHandler() + { + + } + + protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + { + bool serverCommunicationSuccess = false; + + try + { + var response = await base.SendAsync(request, cancellationToken); + + serverCommunicationSuccess = true; + + if (response.IsSuccessStatusCode is false && response.Content.Headers.ContentType?.MediaType?.Contains("application/json", StringComparison.InvariantCultureIgnoreCase) is true) + { + if (response.Headers.TryGetValues("Request-ID", out IEnumerable? values) && values is not null && values.Any()) + { + RestErrorInfo restError = (await response!.Content.ReadFromJsonAsync(AppJsonContext.Default.RestErrorInfo, cancellationToken))!; + + Type exceptionType = typeof(RestErrorInfo).Assembly.GetType(restError.ExceptionType!) ?? typeof(UnknownException); + + var args = new List { restError.Message! }; + + if (exceptionType == typeof(ResourceValidationException)) + { + args.Add(restError.Payload); + } + + Exception exp = (Exception)Activator.CreateInstance(exceptionType, args.ToArray())!; + + throw exp; + } + } + + response.EnsureSuccessStatusCode(); + + return response; + } + catch (Exception exp) when ((exp is HttpRequestException && serverCommunicationSuccess is false) + || exp is TaskCanceledException tcExp && tcExp.InnerException is TimeoutException) + { + throw new ServerConnectionException(nameof(ServerConnectionException), exp); + } + } +} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Client/Services/HttpMessageHandlers/RetryDelegatingHandler.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Services/HttpMessageHandlers/RetryDelegatingHandler.cs new file mode 100644 index 0000000000..6ad709c7c0 --- /dev/null +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Services/HttpMessageHandlers/RetryDelegatingHandler.cs @@ -0,0 +1,55 @@ +namespace Bit.Websites.Sales.Client.Services.HttpMessageHandlers; + +public class RetryDelegatingHandler + : DelegatingHandler +{ + public RetryDelegatingHandler(ExceptionDelegatingHandler handler) + : base(handler) + { + + } + + public RetryDelegatingHandler() + { + + } + + protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + { + var delays = GetDelays(scaleFirstTry: TimeSpan.FromSeconds(3), maxRetries: 3).ToArray(); + + Exception? lastExp = null; + + foreach (var delay in delays) + { + try + { + return await base.SendAsync(request, cancellationToken); + } + catch (Exception exp) when (exp is not KnownException) + { + lastExp = exp; + await Task.Delay(delay, cancellationToken); + } + } + + throw lastExp!; + } + + private static IEnumerable GetDelays(TimeSpan scaleFirstTry, int maxRetries) + { + TimeSpan maxValue = TimeSpan.MaxValue; + var maxTimeSpanDouble = maxValue.Ticks - 1_000.0; + var i = 0; + var targetTicksFirstDelay = scaleFirstTry.Ticks; + var num = 0.0; + for (; i < maxRetries; i++) + { + var num2 = i + Random.Shared.NextDouble(); + var next = Math.Pow(2.0, num2) * Math.Tanh(Math.Sqrt(4.0 * num2)); + var num3 = next - num; + yield return TimeSpan.FromTicks((long)Math.Min(num3 * 0.7_142_857_142_857_143 * targetTicksFirstDelay, maxTimeSpanDouble)); + num = next; + } + } +} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Client/Services/MessageBoxService.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Services/MessageBoxService.cs new file mode 100644 index 0000000000..099a8aec29 --- /dev/null +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Services/MessageBoxService.cs @@ -0,0 +1,12 @@ +namespace Bit.Websites.Sales.Client.Services; +public partial class MessageBoxService +{ + [AutoInject] IPubSubService _pubSubService = default!; + + public async Task Show(string message, string title = "") + { + TaskCompletionSource tsc = new(); + _pubSubService.Publish(PubSubMessages.SHOW_MESSAGE, (message, title, tsc)); + await tsc.Task; + } +} diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Services/StateService.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Services/PrerenderStateService.cs similarity index 75% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/Services/StateService.cs rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/Services/PrerenderStateService.cs index 87f0969697..d4ed1f75b3 100644 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Services/StateService.cs +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Services/PrerenderStateService.cs @@ -1,21 +1,24 @@  -namespace Bit.Websites.Careers.Web.Services; +using Microsoft.AspNetCore.Components.Web; + +namespace Bit.Websites.Sales.Client.Services; // Using this class, persisting the application state on Pre-Rendering mode (explained here: https://docs.microsoft.com/en-us/aspnet/core/blazor/components/prerendering-and-integration#persist-prerendered-state) will be very simple in this multi-mode Template project. -#if (BlazorWebAssembly || BlazorServer) && SSR -public class StateService : IStateService, IAsyncDisposable +public class PrerenderStateService : IPrerenderStateService, IAsyncDisposable { private PersistingComponentStateSubscription? _subscription; private readonly PersistentComponentState _applicationState; - private readonly ConcurrentDictionary _values = new ConcurrentDictionary(); + private readonly ConcurrentDictionary _values = new(); - public StateService(PersistentComponentState applicationState) + public PrerenderStateService(PersistentComponentState applicationState) { _applicationState = applicationState; if (OperatingSystem.IsBrowser() is false) - _subscription = applicationState.RegisterOnPersisting(PersistAsJson); + { + _subscription = applicationState.RegisterOnPersisting(PersistAsJson, RenderModeProvider.Current); + } } public async Task GetValue(string key, Func> factory) @@ -48,12 +51,3 @@ public async ValueTask DisposeAsync() _subscription?.Dispose(); } } -#else -public class StateService : IStateService -{ - public Task GetValue(string key, Func> factory) - { - return factory(); - } -} -#endif diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Client/Services/PubSubMessages.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Services/PubSubMessages.cs new file mode 100644 index 0000000000..49dedcd3df --- /dev/null +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Services/PubSubMessages.cs @@ -0,0 +1,6 @@ +namespace Bit.Websites.Sales.Client.Services; + +public static class PubSubMessages +{ + public const string SHOW_MESSAGE = "SHOWMESSAGE"; +} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Services/PubSubService.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Services/PubSubService.cs similarity index 60% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/Services/PubSubService.cs rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/Services/PubSubService.cs index 99fe2da625..b21204247a 100644 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Services/PubSubService.cs +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Services/PubSubService.cs @@ -1,10 +1,13 @@ -namespace Bit.Websites.Sales.Web.Services; +namespace Bit.Websites.Sales.Client.Services; +/// +/// For more information docs. +/// public class PubSubService : IPubSubService { private readonly ConcurrentDictionary>> _handlers = new(); - public void Pub(string message, object? payload) + public void Publish(string message, object? payload) { if (_handlers.TryGetValue(message, out var handlers)) { @@ -12,11 +15,11 @@ public void Pub(string message, object? payload) } } - public Action Sub(string message, Action handler) + public Action Subscribe(string message, Action handler) { var handlers = _handlers.ContainsKey(message) ? _handlers[message] - : _handlers[message] = new List>(); + : _handlers[message] = []; handlers.Add(handler); diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Client/Services/RenderModeProvider.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Services/RenderModeProvider.cs new file mode 100644 index 0000000000..163e286c18 --- /dev/null +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Services/RenderModeProvider.cs @@ -0,0 +1,18 @@ +using Microsoft.AspNetCore.Components.Web; + +namespace Bit.Websites.Sales.Client.Services; + +public static class RenderModeProvider +{ + static IComponentRenderMode PrerenderEnabledAuto = RenderMode.InteractiveAuto; + static IComponentRenderMode PrerenderEnabledBlazorWasm = RenderMode.InteractiveWebAssembly; + static IComponentRenderMode PrerenderEnabledBlazorServer = RenderMode.InteractiveServer; + + static IComponentRenderMode Auto = new InteractiveAutoRenderMode(prerender: false); + static IComponentRenderMode BlazorWasm = new InteractiveWebAssemblyRenderMode(prerender: false); + static IComponentRenderMode BlazorServer = new InteractiveServerRenderMode(prerender: false); + + // PrerenderOnly: In order to have prerender only mode, simply remove @rendermode usages from App.razor + + public static IComponentRenderMode Current => PrerenderEnabledAuto; +} diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Components/AppComponentBase.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/AppComponentBase.cs similarity index 84% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/Components/AppComponentBase.cs rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/AppComponentBase.cs index e45794b9a2..d46ee2c1d5 100644 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Components/AppComponentBase.cs +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/AppComponentBase.cs @@ -1,24 +1,28 @@ -namespace Bit.Websites.Careers.Web.Components; +namespace Bit.Websites.Sales.Client.Shared; public partial class AppComponentBase : ComponentBase { + [AutoInject] protected IJSRuntime JSRuntime = default!; + [AutoInject] protected HttpClient HttpClient = default!; - [AutoInject] protected IStateService StateService = default!; + /// + /// + /// + [AutoInject] protected IPrerenderStateService PrerenderStateService = default!; + /// + /// + /// [AutoInject] protected IPubSubService PubSubService = default!; [AutoInject] protected IConfiguration Configuration = default!; - [AutoInject] protected IJSRuntime JSRuntime { get; set; } = default!; - [AutoInject] protected NavigationManager NavigationManager = default!; - - [AutoInject] protected IAuthTokenProvider AuthTokenProvider = default!; - + [AutoInject] protected IExceptionHandler ExceptionHandler { get; set; } = default!; - - protected async sealed override Task OnInitializedAsync() + + protected sealed override async Task OnInitializedAsync() { try { @@ -31,7 +35,7 @@ protected async sealed override Task OnInitializedAsync() } } - protected async sealed override Task OnParametersSetAsync() + protected sealed override async Task OnParametersSetAsync() { try { @@ -44,7 +48,15 @@ protected async sealed override Task OnParametersSetAsync() } } - protected async override Task OnAfterRenderAsync(bool firstRender) + /// + /// Replacement for which catches all possible exceptions in order to prevent app crash. + /// + protected virtual Task OnInitAsync() + { + return Task.CompletedTask; + } + + protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender) { @@ -61,12 +73,9 @@ protected async override Task OnAfterRenderAsync(bool firstRender) await base.OnAfterRenderAsync(firstRender); } - /// - /// Replacement for which catches all possible exceptions in order to prevent app crash. - /// - protected virtual Task OnInitAsync() + protected sealed override void OnInitialized() { - return Task.CompletedTask; + base.OnInitialized(); } /// diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Shared/AppErrorBoundary.razor b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/AppErrorBoundary.razor similarity index 96% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/Shared/AppErrorBoundary.razor rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/AppErrorBoundary.razor index 4cb5fa222e..c198a23a93 100644 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Shared/AppErrorBoundary.razor +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/AppErrorBoundary.razor @@ -14,7 +14,7 @@ else if (ErrorContent is null)

Oops, something went wrong...

- @if (ShowException) + @if (_showException) {
@CurrentException?.ToString()
} @@ -27,4 +27,4 @@ else if (ErrorContent is null) else { @ErrorContent(CurrentException) -} +} \ No newline at end of file diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Shared/AppErrorBoundary.razor.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/AppErrorBoundary.razor.cs similarity index 56% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/Shared/AppErrorBoundary.razor.cs rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/AppErrorBoundary.razor.cs index a3713a02ce..aaba38f880 100644 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Shared/AppErrorBoundary.razor.cs +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/AppErrorBoundary.razor.cs @@ -1,30 +1,32 @@ -namespace Bit.Websites.Sales.Web.Shared; + +namespace Bit.Websites.Sales.Client.Shared; +/// +/// https://learn.microsoft.com/en-us/aspnet/core/blazor/fundamentals/handle-errors +/// public partial class AppErrorBoundary { + private bool _showException; + [AutoInject] private IExceptionHandler _exceptionHandler = default!; [AutoInject] private NavigationManager _navigationManager = default!; - private bool ShowException { get; set; } - #if DEBUG protected override void OnInitialized() { - ShowException = true; + _showException = true; } #endif - protected override Task OnErrorAsync(Exception exception) + protected override async Task OnErrorAsync(Exception exception) { _exceptionHandler.Handle(exception); - - return Task.CompletedTask; } private void Refresh() { - _navigationManager.NavigateTo(_navigationManager.Uri, true); + _navigationManager.Refresh(forceReload: true); } private void GoHome() diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Shared/AppErrorBoundary.razor.scss b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/AppErrorBoundary.razor.scss similarity index 67% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/Shared/AppErrorBoundary.razor.scss rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/AppErrorBoundary.razor.scss index 9df1a950c5..8f7dd9ea2e 100644 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Shared/AppErrorBoundary.razor.scss +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/AppErrorBoundary.razor.scss @@ -1,16 +1,16 @@ -@import '../Styles/abstracts/_colors.scss'; -@import '../Styles/abstracts/_functions.scss'; +@import '../Styles/abstracts/_functions.scss'; +@import '../Styles/abstracts/_bit-css-variables.scss'; .main { + width: 100%; display: flex; - flex-direction: column; + padding: rem2(8px); text-align: center; - width: 100%; max-width: rem2(800px); max-height: rem2(600px); - background-color: $White; + flex-direction: column; border-radius: rem2(4px); - padding: rem2(8px); + background-color: $bit-color-background-primary; } .header { @@ -18,14 +18,13 @@ } .title { - color: $Red; + color: $bit-color-state-error; } .exception { - color: $Black; - white-space: pre; overflow: auto; text-align: left; + white-space: pre; margin: rem2(24px); } diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Shared/ChangeResponseStatusCode.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/ChangePrerenderResponseStatusCode.cs similarity index 73% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/Shared/ChangeResponseStatusCode.cs rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/ChangePrerenderResponseStatusCode.cs index 89173abd1c..c5441adfdd 100644 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Shared/ChangeResponseStatusCode.cs +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/ChangePrerenderResponseStatusCode.cs @@ -1,8 +1,11 @@ using System.Net; -namespace Bit.Websites.Careers.Web.Shared; +namespace Bit.Websites.Sales.Client.Shared; -public partial class ChangeResponseStatusCode : AppComponentBase +/// +/// This component is used during prerendering to determine the value of the StatusCode parameter for the returned HTTP response. +/// +public partial class ChangePrerenderResponseStatusCode : AppComponentBase { [Parameter] public HttpStatusCode StatusCode { get; set; } @@ -14,7 +17,7 @@ public partial class ChangeResponseStatusCode : AppComponentBase protected override Task OnInitAsync() { - if (_httpContextAccessorType is not null && BlazorModeDetector.Current.IsBlazorWebAssembly()) + if (_httpContextAccessorType is not null) { var httpContextAccessor = _serviceProvider.GetService(_httpContextAccessorType); diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Shared/ContactForm.razor b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/ContactForm.razor similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/Shared/ContactForm.razor rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/ContactForm.razor diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Shared/ContactForm.razor.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/ContactForm.razor.cs similarity index 89% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/Shared/ContactForm.razor.cs rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/ContactForm.razor.cs index a045d13cb6..cbddf72384 100644 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Shared/ContactForm.razor.cs +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/ContactForm.razor.cs @@ -1,6 +1,6 @@ using Bit.Websites.Sales.Shared.Dtos.ContactUs; -namespace Bit.Websites.Sales.Web.Shared; +namespace Bit.Websites.Sales.Client.Shared; public partial class ContactForm { @@ -32,7 +32,7 @@ private async Task DoSubmit() } catch (KnownException e) { - _errorMessage = AppStrings.ResourceManager.Translate(e.Message); + _errorMessage = e.Message; } finally { diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Shared/ContactForm.razor.scss b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/ContactForm.razor.scss similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/Shared/ContactForm.razor.scss rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/ContactForm.razor.scss diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Shared/Footer.razor b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/Footer.razor similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/Shared/Footer.razor rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/Footer.razor diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Shared/Footer.razor.scss b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/Footer.razor.scss similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/Shared/Footer.razor.scss rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/Footer.razor.scss diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Shared/Header.razor b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/Header.razor similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/Shared/Header.razor rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/Header.razor diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Shared/Header.razor.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/Header.razor.cs similarity index 90% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/Shared/Header.razor.cs rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/Header.razor.cs index 695dfcebfe..c2aa036148 100644 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Shared/Header.razor.cs +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/Header.razor.cs @@ -1,4 +1,4 @@ -namespace Bit.Websites.Sales.Web.Shared; +namespace Bit.Websites.Sales.Client.Shared; public partial class Header { @@ -8,13 +8,13 @@ public partial class Header [AutoInject] private NavigationManager _navigationManager = default!; [AutoInject] private IJSRuntime _js = default!; - protected override void OnInitialized() + protected override async Task OnInitAsync() { _navigationManager.LocationChanged += OnLocationChanged; SetCurrentUrl(); - base.OnInitialized(); + await base.OnInitAsync(); } private void OnLocationChanged(object? sender, Microsoft.AspNetCore.Components.Routing.LocationChangedEventArgs e) diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Shared/Header.razor.scss b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/Header.razor.scss similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/Shared/Header.razor.scss rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/Header.razor.scss diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Shared/LoadingComponent.razor b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/LoadingComponent.razor similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/Shared/LoadingComponent.razor rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/LoadingComponent.razor diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Shared/LoadingComponent.razor.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/LoadingComponent.razor.cs similarity index 69% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/Shared/LoadingComponent.razor.cs rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/LoadingComponent.razor.cs index 52cf87c986..02b6738792 100644 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Shared/LoadingComponent.razor.cs +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/LoadingComponent.razor.cs @@ -1,4 +1,4 @@ -namespace Bit.Websites.Careers.Web.Shared; +namespace Bit.Websites.Sales.Client.Shared; public partial class LoadingComponent { diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Shared/LoadingComponent.razor.scss b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/LoadingComponent.razor.scss similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/Shared/LoadingComponent.razor.scss rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/LoadingComponent.razor.scss diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Shared/MainLayout.razor b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/MainLayout.razor similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/Shared/MainLayout.razor rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/MainLayout.razor diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Shared/MainLayout.razor.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/MainLayout.razor.cs similarity index 90% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/Shared/MainLayout.razor.cs rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/MainLayout.razor.cs index 438890d3ec..646c91d553 100644 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Shared/MainLayout.razor.cs +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/MainLayout.razor.cs @@ -1,4 +1,4 @@ -namespace Bit.Websites.Sales.Web.Shared; +namespace Bit.Websites.Sales.Client.Shared; public partial class MainLayout { diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Shared/MainLayout.razor.scss b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/MainLayout.razor.scss similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/Shared/MainLayout.razor.scss rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/MainLayout.razor.scss diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Shared/MessageBox.razor b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/MessageBox.razor similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/Shared/MessageBox.razor rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/MessageBox.razor diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/MessageBox.razor.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/MessageBox.razor.cs new file mode 100644 index 0000000000..d5100fdc46 --- /dev/null +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/MessageBox.razor.cs @@ -0,0 +1,73 @@ +namespace Bit.Websites.Sales.Client.Shared; + +public partial class MessageBox : IDisposable +{ + private bool _isOpen; + private string? _title; + private string? _body; + + private TaskCompletionSource? _tsc; + + private async Task OnCloseClick() + { + _isOpen = false; + await JSRuntime.ToggleBodyOverflow(false); + _tsc?.SetResult(null); + _tsc = null; + } + + private async Task OnOkClick() + { + _isOpen = false; + await JSRuntime.ToggleBodyOverflow(false); + _tsc?.SetResult(null); + _tsc = null; + } + + Action? _dispose; + bool _disposed = false; + + protected override Task OnInitAsync() + { + _dispose = PubSubService.Subscribe(PubSubMessages.SHOW_MESSAGE, async args => + { + (var message, string title, TaskCompletionSource tsc) = ((string message, string title, TaskCompletionSource tsc))args!; + await (_tsc?.Task ?? Task.CompletedTask); + _tsc = tsc; + await ShowMessageBox(message, title); + }); + + return base.OnInitAsync(); + } + + private async Task ShowMessageBox(string message, string title = "") + { + await InvokeAsync(() => + { + _ = JSRuntime.ToggleBodyOverflow(true); + + _isOpen = true; + _title = title; + _body = message; + + StateHasChanged(); + }); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (_disposed || disposing is false) return; + + _tsc?.TrySetResult(null); + _tsc = null; + _dispose?.Invoke(); + + _disposed = true; + } +} diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Shared/MessageBox.razor.scss b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/MessageBox.razor.scss similarity index 84% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/Shared/MessageBox.razor.scss rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/MessageBox.razor.scss index 6f73a0fc27..bbf208cc52 100644 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Shared/MessageBox.razor.scss +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/MessageBox.razor.scss @@ -1,10 +1,11 @@ @import '../Styles/abstracts/_functions.scss'; +@import '../Styles/abstracts/_media-queries.scss'; .main { flex-grow: 1; display: flex; - flex-direction: column; padding: rem2(10px); + flex-direction: column; } .header { @@ -16,12 +17,12 @@ } .body { - display: flex; flex-grow: 1; - margin: rem2(10px) 0; - white-space: pre; + display: flex; overflow: auto; - max-width: rem2(960px); + max-width: 90vw; + white-space: pre; + margin: rem2(10px) 0; } .footer { diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/PageNotFound.razor b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/PageNotFound.razor new file mode 100644 index 0000000000..291f7cb44f --- /dev/null +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/PageNotFound.razor @@ -0,0 +1,15 @@ +@inherits AppComponentBase + + + +
+
+
+
+
+
+
Page Not Found
+
+
+ Go Back +
\ No newline at end of file diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/PageNotFound.razor.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/PageNotFound.razor.cs new file mode 100644 index 0000000000..466473a6f6 --- /dev/null +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/PageNotFound.razor.cs @@ -0,0 +1,11 @@ +namespace Bit.Websites.Sales.Client.Shared; + +public partial class PageNotFound +{ + [AutoInject] public NavigationManager NavigationManager { get; set; } + + private void BackToHome() + { + NavigationManager.NavigateTo("/"); + } +} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Components/PageNotFound.razor.scss b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/PageNotFound.razor.scss similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/Components/PageNotFound.razor.scss rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/Shared/PageNotFound.razor.scss diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Client/Styles/abstracts/_bit-css-variables.scss b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Styles/abstracts/_bit-css-variables.scss new file mode 100644 index 0000000000..b715b9c518 --- /dev/null +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Styles/abstracts/_bit-css-variables.scss @@ -0,0 +1,123 @@ +/*-------- Colors --------*/ +$bit-color-primary-main: var(--bit-clr-primary-main); +$bit-color-primary-dark: var(--bit-clr-primary-dark); +$bit-color-primary-light: var(--bit-clr-primary-light); +$bit-color-primary-text: var(--bit-clr-primary-text); + +$bit-color-secondary-main: var(--bit-clr-secondary-main); +$bit-color-secondary-dark: var(--bit-clr-secondary-dark); +$bit-color-secondary-light: var(--bit-clr-secondary-light); +$bit-color-secondary-text: var(--bit-clr-secondary-text); + +//foreground +$bit-color-foreground-primary: var(--bit-clr-fg-primary); +$bit-color-foreground-secondary: var(--bit-clr-fg-secondary); +$bit-color-foreground-disabled: var(--bit-clr-fg-disabled); + +//backgrounds +$bit-color-background-primary: var(--bit-clr-bg-primary); +$bit-color-background-secondary: var(--bit-clr-bg-secondary); +$bit-color-background-disabled: var(--bit-clr-bg-disabled); +$bit-color-background-overlay: var(--bit-clr-bg-overlay); + +//borders +$bit-color-border-primary: var(--bit-clr-brd-primary); +$bit-color-border-secondary: var(--bit-clr-brd-secondary); +$bit-color-border-disabled: var(--bit-clr-brd-disabled); + +//actions +$bit-color-action-hover-primary: var(--bit-clr-act-hover-pri); +$bit-color-action-active-primary: var(--bit-clr-act-active-pri); +$bit-color-action-hover-primary-dark: var(--bit-clr-act-hover-pri-dark); +$bit-color-action-active-primary-dark: var(--bit-clr-act-active-pri-dark); +$bit-color-action-hover-primary-light: var(--bit-clr-act-hover-pri-light); +$bit-color-action-active-primary-light: var(--bit-clr-act-active-pri-light); +$bit-color-action-hover-secondary: var(--bit-clr-act-hover-sec); +$bit-color-action-active-secondary: var(--bit-clr-act-active-sec); +$bit-color-action-hover-secondary-dark: var(--bit-clr-act-hover-sec-dark); +$bit-color-action-active-secondary-dark: var(--bit-clr-act-active-sec-dark); +$bit-color-action-hover-secondary-light: var(--bit-clr-act-hover-sec-light); +$bit-color-action-active-secondary-light: var(--bit-clr-act-active-sec-light); +//actions-foreground +$bit-color-action-hover-foreground-primary: var(--bit-clr-act-hover-fg-pri); +$bit-color-action-active-foreground-primary: var(--bit-clr-act-active-fg-pri); +$bit-color-action-hover-foreground-secondary: var(--bit-clr-act-hover-fg-sec); +$bit-color-action-active-foreground-secondary: var(--bit-clr-act-hover-fg-sec); +//actions-backgrounds +$bit-color-action-hover-background-primary: var(--bit-clr-act-hover-bg-pri); +$bit-color-action-active-background-primary: var(--bit-clr-act-active-bg-pri); +$bit-color-action-hover-background-secondary: var(--bit-clr-act-hover-bg-sec); +$bit-color-action-active-background-secondary: var(--bit-clr-act-active-bg-sec); +//actions-borders +$bit-color-action-hover-border-primary: var(--bit-clr-act-hover-brd-pri); +$bit-color-action-active-border-primary: var(--bit-clr-act-active-brd-pri); +$bit-color-action-hover-border-secondary: var(--bit-clr-act-hover-brd-sec); +$bit-color-action-active-border-secondary: var(--bit-clr-act-active-brd-sec); + +//states +$bit-color-state-info: var(--bit-clr-sta-info); +$bit-color-state-info-bg: var(--bit-clr-sta-info-bg); +$bit-color-state-success: var(--bit-clr-sta-success); +$bit-color-state-success-bg: var(--bit-clr-sta-success-bg); +$bit-color-state-warning: var(--bit-clr-sta-warning); +$bit-color-state-warning-bg: var(--bit-clr-sta-warning-bg); +$bit-color-state-severe-warning: var(--bit-clr-sta-severe-warning); +$bit-color-state-severe-warning-bg: var(--bit-clr-sta-severe-warning-bg); +$bit-color-state-error: var(--bit-clr-sta-error); +$bit-color-state-error-bg: var(--bit-clr-sta-error-bg); +$bit-color-state-required: var(--bit-clr-sta-req); + +//neutrals +$bit-color-neutrals-white: var(--bit-clr-ntr-white); +$bit-color-neutrals-black: var(--bit-clr-ntr-black); +$bit-color-neutrals-gray10: var(--bit-clr-ntr-gray10); +$bit-color-neutrals-gray20: var(--bit-clr-ntr-gray20); +$bit-color-neutrals-gray30: var(--bit-clr-ntr-gray30); +$bit-color-neutrals-gray40: var(--bit-clr-ntr-gray40); +$bit-color-neutrals-gray50: var(--bit-clr-ntr-gray50); +$bit-color-neutrals-gray60: var(--bit-clr-ntr-gray60); +$bit-color-neutrals-gray70: var(--bit-clr-ntr-gray70); +$bit-color-neutrals-gray80: var(--bit-clr-ntr-gray80); +$bit-color-neutrals-gray90: var(--bit-clr-ntr-gray90); +$bit-color-neutrals-gray100: var(--bit-clr-ntr-gray100); +$bit-color-neutrals-gray110: var(--bit-clr-ntr-gray110); +$bit-color-neutrals-gray120: var(--bit-clr-ntr-gray120); +$bit-color-neutrals-gray130: var(--bit-clr-ntr-gray130); +$bit-color-neutrals-gray140: var(--bit-clr-ntr-gray140); +$bit-color-neutrals-gray150: var(--bit-clr-ntr-gray150); +$bit-color-neutrals-gray160: var(--bit-clr-ntr-gray160); +$bit-color-neutrals-gray170: var(--bit-clr-ntr-gray170); +$bit-color-neutrals-gray180: var(--bit-clr-ntr-gray180); +$bit-color-neutrals-gray190: var(--bit-clr-ntr-gray190); +$bit-color-neutrals-gray200: var(--bit-clr-ntr-gray200); +$bit-color-neutrals-gray210: var(--bit-clr-ntr-gray210); +$bit-color-neutrals-gray220: var(--bit-clr-ntr-gray220); + +//shadows-callout +$bit-box-shadow-callout: var(--bit-shd-cal); + +//shadows +$bit-box-shadow-1: var(--bit-shd-1); +$bit-box-shadow-2: var(--bit-shd-2); +$bit-box-shadow-3: var(--bit-shd-3); +$bit-box-shadow-4: var(--bit-shd-4); +$bit-box-shadow-5: var(--bit-shd-5); +$bit-box-shadow-6: var(--bit-shd-6); +$bit-box-shadow-7: var(--bit-shd-7); +$bit-box-shadow-8: var(--bit-shd-8); +$bit-box-shadow-9: var(--bit-shd-9); +$bit-box-shadow-10: var(--bit-shd-10); +$bit-box-shadow-11: var(--bit-shd-11); +$bit-box-shadow-12: var(--bit-shd-12); +$bit-box-shadow-13: var(--bit-shd-13); +$bit-box-shadow-14: var(--bit-shd-14); +$bit-box-shadow-15: var(--bit-shd-15); +$bit-box-shadow-16: var(--bit-shd-16); +$bit-box-shadow-17: var(--bit-shd-17); +$bit-box-shadow-18: var(--bit-shd-18); +$bit-box-shadow-19: var(--bit-shd-19); +$bit-box-shadow-20: var(--bit-shd-20); +$bit-box-shadow-21: var(--bit-shd-21); +$bit-box-shadow-22: var(--bit-shd-22); +$bit-box-shadow-23: var(--bit-shd-23); +$bit-box-shadow-24: var(--bit-shd-24); diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Styles/abstracts/_colors.scss b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Styles/abstracts/_colors.scss similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/Styles/abstracts/_colors.scss rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/Styles/abstracts/_colors.scss diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Styles/abstracts/_functions.scss b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Styles/abstracts/_functions.scss similarity index 100% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/Styles/abstracts/_functions.scss rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/Styles/abstracts/_functions.scss diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Styles/abstracts/_media-queries.scss b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Styles/abstracts/_media-queries.scss similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/Styles/abstracts/_media-queries.scss rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/Styles/abstracts/_media-queries.scss diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Styles/abstracts/_mixins.scss b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Styles/abstracts/_mixins.scss similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/Styles/abstracts/_mixins.scss rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/Styles/abstracts/_mixins.scss diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Styles/app.scss b/src/Websites/Sales/src/Bit.Websites.Sales.Client/Styles/app.scss similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/Styles/app.scss rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/Styles/app.scss diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/_Imports.razor b/src/Websites/Sales/src/Bit.Websites.Sales.Client/_Imports.razor similarity index 56% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/_Imports.razor rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/_Imports.razor index e730afce8c..c3a149b89d 100644 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Web/_Imports.razor +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Client/_Imports.razor @@ -1,17 +1,17 @@ @using System.Reflection -@using System.Globalization +@using Microsoft.JSInterop +@using Microsoft.Extensions.Logging @using Microsoft.AspNetCore.Components +@using Microsoft.Extensions.Configuration @using Microsoft.AspNetCore.Components.Web @using Microsoft.AspNetCore.Components.Forms @using Microsoft.AspNetCore.Components.Routing @using Microsoft.AspNetCore.Components.Web.Virtualization -@using Microsoft.Extensions.Configuration -@using Microsoft.JSInterop @using Bit.BlazorUI @using Bit.Websites.Sales -@using Bit.Websites.Sales.Web -@using Bit.Websites.Sales.Web.Shared -@using Bit.Websites.Sales.Web.Pages -@using Bit.Websites.Sales.Web.Components -@using Bit.Websites.Sales.Web.Services.Contracts -@using Bit.Websites.Sales.Web.Services \ No newline at end of file +@using Bit.Websites.Sales.Client +@using Bit.Websites.Sales.Client.Shared +@using Bit.Websites.Sales.Client.Components +@using Bit.Websites.Sales.Client.Pages +@using Bit.Websites.Sales.Client.Services.Contracts +@using Bit.Websites.Sales.Client.Services \ No newline at end of file diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/appsettings.json b/src/Websites/Sales/src/Bit.Websites.Sales.Client/appsettings.json similarity index 63% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/appsettings.json rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/appsettings.json index b9c9813941..423ad00545 100644 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Web/appsettings.json +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Client/appsettings.json @@ -7,9 +7,6 @@ "Microsoft.Hosting.Lifetime": "Information" } }, - "GoogleTagManager": { - "Id": "" - }, "AllowedHosts": "*", - "ApiServerAddress": "https://localhost:5001/api/" + "ApiServerAddress": "api/" // You can also use absolute urls such as http://192.168.1.150:5000/api/ or https://todob.bitplatform.dev/api/ } diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/compilerconfig.json b/src/Websites/Sales/src/Bit.Websites.Sales.Client/compilerconfig.json similarity index 99% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/compilerconfig.json rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/compilerconfig.json index 43cf2d7b96..188383723c 100644 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Web/compilerconfig.json +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Client/compilerconfig.json @@ -1,4 +1,4 @@ -[ +[ { "outputFile": "Pages/CasesPage.razor.css", "inputFile": "Pages/CasesPage.razor.scss", diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/tsconfig.json b/src/Websites/Sales/src/Bit.Websites.Sales.Client/tsconfig.json similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/tsconfig.json rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/tsconfig.json diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/favicon.ico b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/favicon.ico similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/favicon.ico rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/favicon.ico diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/fonts/OpenSans-Bold.woff2 b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/fonts/OpenSans-Bold.woff2 similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/fonts/OpenSans-Bold.woff2 rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/fonts/OpenSans-Bold.woff2 diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/fonts/OpenSans-Medium.woff2 b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/fonts/OpenSans-Medium.woff2 similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/fonts/OpenSans-Medium.woff2 rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/fonts/OpenSans-Medium.woff2 diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/fonts/OpenSans-MediumItalic.woff2 b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/fonts/OpenSans-MediumItalic.woff2 similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/fonts/OpenSans-MediumItalic.woff2 rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/fonts/OpenSans-MediumItalic.woff2 diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/fonts/OpenSans-Regular.woff2 b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/fonts/OpenSans-Regular.woff2 similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/fonts/OpenSans-Regular.woff2 rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/fonts/OpenSans-Regular.woff2 diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/fonts/OpenSans-SemiBold.woff2 b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/fonts/OpenSans-SemiBold.woff2 similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/fonts/OpenSans-SemiBold.woff2 rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/fonts/OpenSans-SemiBold.woff2 diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/about/about_bg.webp b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/about/about_bg.webp similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/about/about_bg.webp rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/about/about_bg.webp diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/about/guarantee/customer-first_bg.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/about/guarantee/customer-first_bg.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/about/guarantee/customer-first_bg.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/about/guarantee/customer-first_bg.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/about/guarantee/integrity_bg.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/about/guarantee/integrity_bg.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/about/guarantee/integrity_bg.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/about/guarantee/integrity_bg.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/about/guarantee/performance_bg.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/about/guarantee/performance_bg.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/about/guarantee/performance_bg.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/about/guarantee/performance_bg.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/about/guarantee/quality_bg.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/about/guarantee/quality_bg.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/about/guarantee/quality_bg.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/about/guarantee/quality_bg.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/about/guarantee/technical-skill_bg.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/about/guarantee/technical-skill_bg.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/about/guarantee/technical-skill_bg.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/about/guarantee/technical-skill_bg.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/about/integrity-icon.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/about/integrity-icon.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/about/integrity-icon.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/about/integrity-icon.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/about/performance-icon.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/about/performance-icon.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/about/performance-icon.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/about/performance-icon.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/about/qoute-icon.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/about/qoute-icon.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/about/qoute-icon.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/about/qoute-icon.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/about/quality-icon.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/about/quality-icon.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/about/quality-icon.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/about/quality-icon.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/about/skills-icon.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/about/skills-icon.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/about/skills-icon.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/about/skills-icon.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/about/sustainability-icon.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/about/sustainability-icon.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/about/sustainability-icon.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/about/sustainability-icon.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/about/team-image.webp b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/about/team-image.webp similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/about/team-image.webp rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/about/team-image.webp diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/about/team/team-1.webp b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/about/team/team-1.webp similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/about/team/team-1.webp rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/about/team/team-1.webp diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/about/team/team-2.webp b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/about/team/team-2.webp similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/about/team/team-2.webp rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/about/team/team-2.webp diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/about/team/team-3.webp b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/about/team/team-3.webp similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/about/team/team-3.webp rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/about/team/team-3.webp diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/about/team/team-4.webp b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/about/team/team-4.webp similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/about/team/team-4.webp rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/about/team/team-4.webp diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/all-cases/bit_case_bg.webp b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/all-cases/bit_case_bg.webp similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/all-cases/bit_case_bg.webp rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/all-cases/bit_case_bg.webp diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/all-cases/delivery-time_bg.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/all-cases/delivery-time_bg.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/all-cases/delivery-time_bg.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/all-cases/delivery-time_bg.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/all-cases/mining_case_bg.webp b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/all-cases/mining_case_bg.webp similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/all-cases/mining_case_bg.webp rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/all-cases/mining_case_bg.webp diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/all-cases/retail_case_bg.webp b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/all-cases/retail_case_bg.webp similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/all-cases/retail_case_bg.webp rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/all-cases/retail_case_bg.webp diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/all-cases/tag_ai.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/all-cases/tag_ai.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/all-cases/tag_ai.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/all-cases/tag_ai.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/all-cases/tag_bi.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/all-cases/tag_bi.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/all-cases/tag_bi.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/all-cases/tag_bi.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/all-cases/tag_cld.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/all-cases/tag_cld.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/all-cases/tag_cld.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/all-cases/tag_cld.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/all-cases/tag_cloud.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/all-cases/tag_cloud.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/all-cases/tag_cloud.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/all-cases/tag_cloud.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/all-cases/tag_iot.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/all-cases/tag_iot.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/all-cases/tag_iot.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/all-cases/tag_iot.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/all-cases/tag_mob.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/all-cases/tag_mob.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/all-cases/tag_mob.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/all-cases/tag_mob.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/all-cases/tag_sup.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/all-cases/tag_sup.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/all-cases/tag_sup.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/all-cases/tag_sup.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/all-cases/tag_ui.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/all-cases/tag_ui.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/all-cases/tag_ui.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/all-cases/tag_ui.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/all-cases/tag_vis.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/all-cases/tag_vis.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/all-cases/tag_vis.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/all-cases/tag_vis.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/all-cases/tag_vr.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/all-cases/tag_vr.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/all-cases/tag_vr.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/all-cases/tag_vr.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/all-cases/tag_web.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/all-cases/tag_web.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/all-cases/tag_web.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/all-cases/tag_web.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/all-cases/team-members_bg.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/all-cases/team-members_bg.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/all-cases/team-members_bg.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/all-cases/team-members_bg.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/arrow-right-icon.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/arrow-right-icon.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/arrow-right-icon.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/arrow-right-icon.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/arrow-right-orange-icon.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/arrow-right-orange-icon.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/arrow-right-orange-icon.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/arrow-right-orange-icon.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/calendar-dark-icon.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/calendar-dark-icon.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/calendar-dark-icon.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/calendar-dark-icon.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/calendar-white-icon.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/calendar-white-icon.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/calendar-white-icon.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/calendar-white-icon.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/case-curly-divider-img.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/case-curly-divider-img.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/case-curly-divider-img.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/case-curly-divider-img.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/case-photo.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/case-photo.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/case-photo.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/case-photo.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/cases-header-bg.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/cases-header-bg.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/cases-header-bg.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/cases-header-bg.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/cases_bg.webp b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/cases_bg.webp similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/cases_bg.webp rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/cases_bg.webp diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/challenges-bg.png b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/challenges-bg.png similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/challenges-bg.png rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/challenges-bg.png diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/challenges-icon.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/challenges-icon.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/challenges-icon.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/challenges-icon.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/computer-photo.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/computer-photo.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/computer-photo.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/computer-photo.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/polygon-orange-icon.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/polygon-orange-icon.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/polygon-orange-icon.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/polygon-orange-icon.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/result-bg.png b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/result-bg.png similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/result-bg.png rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/result-bg.png diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/result-icon.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/result-icon.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/result-icon.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/result-icon.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/service/artificial-intelligence-icon.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/service/artificial-intelligence-icon.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/service/artificial-intelligence-icon.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/service/artificial-intelligence-icon.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/service/cloud-icon.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/service/cloud-icon.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/service/cloud-icon.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/service/cloud-icon.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/service/mobile-development-icon.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/service/mobile-development-icon.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/service/mobile-development-icon.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/service/mobile-development-icon.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/service/support-icon.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/service/support-icon.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/service/support-icon.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/service/support-icon.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/service/ui-ux-icon.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/service/ui-ux-icon.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/service/ui-ux-icon.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/service/ui-ux-icon.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/service/web-development-icon.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/service/web-development-icon.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/service/web-development-icon.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/service/web-development-icon.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/solutions-bg.png b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/solutions-bg.png similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/solutions-bg.png rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/solutions-bg.png diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/solutions-icon.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/solutions-icon.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/solutions-icon.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/solutions-icon.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/tech/html5-color-icon.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/tech/html5-color-icon.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/tech/html5-color-icon.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/tech/html5-color-icon.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/tech/python-gray-icon.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/tech/python-gray-icon.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/tech/python-gray-icon.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/tech/python-gray-icon.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/tooltip-vector.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/tooltip-vector.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/tooltip-vector.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/tooltip-vector.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/user-icon.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/user-icon.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/cases/user-icon.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/cases/user-icon.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/home/ArrowCircleLeft.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/home/ArrowCircleLeft.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/home/ArrowCircleLeft.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/home/ArrowCircleLeft.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/home/ArrowCircleRight.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/home/ArrowCircleRight.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/home/ArrowCircleRight.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/home/ArrowCircleRight.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/home/MacBook Pro 16 inch.png b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/home/MacBook Pro 16 inch.png similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/home/MacBook Pro 16 inch.png rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/home/MacBook Pro 16 inch.png diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/home/arrow-left-blue-icon.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/home/arrow-left-blue-icon.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/home/arrow-left-blue-icon.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/home/arrow-left-blue-icon.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/home/arrow-right-blue-icon.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/home/arrow-right-blue-icon.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/home/arrow-right-blue-icon.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/home/arrow-right-blue-icon.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/home/home_bg.webp b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/home/home_bg.webp similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/home/home_bg.webp rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/home/home_bg.webp diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/home/process/process-no-1.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/home/process/process-no-1.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/home/process/process-no-1.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/home/process/process-no-1.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/home/process/process-no-2.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/home/process/process-no-2.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/home/process/process-no-2.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/home/process/process-no-2.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/home/process/process-no-3.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/home/process/process-no-3.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/home/process/process-no-3.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/home/process/process-no-3.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/home/process/process-no-4.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/home/process/process-no-4.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/home/process/process-no-4.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/home/process/process-no-4.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/home/process/process-no-5.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/home/process/process-no-5.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/home/process/process-no-5.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/home/process/process-no-5.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/home/process/process1_bg.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/home/process/process1_bg.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/home/process/process1_bg.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/home/process/process1_bg.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/home/process/process2_bg.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/home/process/process2_bg.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/home/process/process2_bg.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/home/process/process2_bg.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/home/process/process3_bg.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/home/process/process3_bg.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/home/process/process3_bg.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/home/process/process3_bg.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/home/process/process4_bg.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/home/process/process4_bg.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/home/process/process4_bg.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/home/process/process4_bg.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/home/process/process5_bg.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/home/process/process5_bg.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/home/process/process5_bg.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/home/process/process5_bg.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/home/services/ai-icon.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/home/services/ai-icon.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/home/services/ai-icon.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/home/services/ai-icon.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/home/services/app-development-icon.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/home/services/app-development-icon.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/home/services/app-development-icon.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/home/services/app-development-icon.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/home/services/cloud-icon.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/home/services/cloud-icon.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/home/services/cloud-icon.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/home/services/cloud-icon.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/home/services/consulting-services-icon.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/home/services/consulting-services-icon.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/home/services/consulting-services-icon.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/home/services/consulting-services-icon.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/home/services/game-development-icon.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/home/services/game-development-icon.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/home/services/game-development-icon.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/home/services/game-development-icon.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/home/services/mobile-development-icon.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/home/services/mobile-development-icon.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/home/services/mobile-development-icon.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/home/services/mobile-development-icon.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/home/services/support-icon.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/home/services/support-icon.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/home/services/support-icon.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/home/services/support-icon.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/home/services/uiux-icon.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/home/services/uiux-icon.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/home/services/uiux-icon.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/home/services/uiux-icon.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/home/services/web-development-icon.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/home/services/web-development-icon.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/home/services/web-development-icon.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/home/services/web-development-icon.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/home/slide.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/home/slide.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/home/slide.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/home/slide.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/home/team-photo.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/home/team-photo.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/home/team-photo.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/home/team-photo.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/home/to-the-moon-bg.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/home/to-the-moon-bg.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/home/to-the-moon-bg.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/home/to-the-moon-bg.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/icons/bit-icon-512.png b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/icons/bit-icon-512.png similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/icons/bit-icon-512.png rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/icons/bit-icon-512.png diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/og-image.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/og-image.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/og-image.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/og-image.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/process/benefit/benefit_card_1.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/process/benefit/benefit_card_1.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/process/benefit/benefit_card_1.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/process/benefit/benefit_card_1.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/process/benefit/benefit_card_2.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/process/benefit/benefit_card_2.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/process/benefit/benefit_card_2.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/process/benefit/benefit_card_2.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/process/benefit/benefit_card_3.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/process/benefit/benefit_card_3.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/process/benefit/benefit_card_3.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/process/benefit/benefit_card_3.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/process/desiner-bg.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/process/desiner-bg.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/process/desiner-bg.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/process/desiner-bg.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/process/developer-bg.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/process/developer-bg.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/process/developer-bg.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/process/developer-bg.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/process/handshake-icon.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/process/handshake-icon.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/process/handshake-icon.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/process/handshake-icon.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/process/header-bg.png b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/process/header-bg.png similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/process/header-bg.png rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/process/header-bg.png diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/process/invoice-icon.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/process/invoice-icon.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/process/invoice-icon.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/process/invoice-icon.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/process/people/people_bg.webp b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/process/people/people_bg.webp similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/process/people/people_bg.webp rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/process/people/people_bg.webp diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/process/process-bg.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/process/process-bg.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/process/process-bg.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/process/process-bg.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/process/process_bg.webp b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/process/process_bg.webp similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/process/process_bg.webp rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/process/process_bg.webp diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/process/project-manager-bg.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/process/project-manager-bg.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/process/project-manager-bg.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/process/project-manager-bg.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/process/qa-tester-bg.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/process/qa-tester-bg.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/process/qa-tester-bg.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/process/qa-tester-bg.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/process/scrum-master-bg.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/process/scrum-master-bg.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/process/scrum-master-bg.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/process/scrum-master-bg.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/process/sw-dev/sw_dev_1.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/process/sw-dev/sw_dev_1.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/process/sw-dev/sw_dev_1.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/process/sw-dev/sw_dev_1.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/process/sw-dev/sw_dev_2.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/process/sw-dev/sw_dev_2.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/process/sw-dev/sw_dev_2.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/process/sw-dev/sw_dev_2.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/process/sw-dev/sw_dev_3.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/process/sw-dev/sw_dev_3.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/process/sw-dev/sw_dev_3.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/process/sw-dev/sw_dev_3.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/process/sw-dev/sw_dev_4.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/process/sw-dev/sw_dev_4.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/process/sw-dev/sw_dev_4.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/process/sw-dev/sw_dev_4.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/process/sw-dev/sw_dev_5.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/process/sw-dev/sw_dev_5.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/process/sw-dev/sw_dev_5.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/process/sw-dev/sw_dev_5.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/process/sw-dev/sw_dev_bg.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/process/sw-dev/sw_dev_bg.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/process/sw-dev/sw_dev_bg.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/process/sw-dev/sw_dev_bg.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/process/transparency-icon.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/process/transparency-icon.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/process/transparency-icon.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/process/transparency-icon.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/services/arrow-down-icon.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/services/arrow-down-icon.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/services/arrow-down-icon.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/services/arrow-down-icon.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/services/arrow-right-icon.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/services/arrow-right-icon.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/services/arrow-right-icon.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/services/arrow-right-icon.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/services/curly-divider.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/services/curly-divider.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/services/curly-divider.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/services/curly-divider.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/services/header-bg.png b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/services/header-bg.png similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/services/header-bg.png rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/services/header-bg.png diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/services/outsourcing/outsourcing_bg_1.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/services/outsourcing/outsourcing_bg_1.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/services/outsourcing/outsourcing_bg_1.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/services/outsourcing/outsourcing_bg_1.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/services/outsourcing/outsourcing_bg_2.webp b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/services/outsourcing/outsourcing_bg_2.webp similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/services/outsourcing/outsourcing_bg_2.webp rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/services/outsourcing/outsourcing_bg_2.webp diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/services/people-bg.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/services/people-bg.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/services/people-bg.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/services/people-bg.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/services/services_bg.webp b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/services/services_bg.webp similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/services/services_bg.webp rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/services/services_bg.webp diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/shared/address_bg.webp b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/shared/address_bg.webp similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/shared/address_bg.webp rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/shared/address_bg.webp diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/shared/bit-logo.png b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/shared/bit-logo.png similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/shared/bit-logo.png rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/shared/bit-logo.png diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/shared/email-icon.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/shared/email-icon.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/shared/email-icon.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/shared/email-icon.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/shared/github-icon.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/shared/github-icon.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/shared/github-icon.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/shared/github-icon.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/shared/linkedin-icon.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/shared/linkedin-icon.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/shared/linkedin-icon.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/shared/linkedin-icon.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/shared/location-icon.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/shared/location-icon.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/shared/location-icon.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/shared/location-icon.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/shared/menu-close-icon.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/shared/menu-close-icon.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/shared/menu-close-icon.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/shared/menu-close-icon.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/shared/menu-icon.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/shared/menu-icon.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/shared/menu-icon.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/shared/menu-icon.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/shared/tel-icon.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/shared/tel-icon.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/shared/tel-icon.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/shared/tel-icon.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/shared/whatsapp-icon.svg b/src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/shared/whatsapp-icon.svg similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Web/wwwroot/images/shared/whatsapp-icon.svg rename to src/Websites/Sales/src/Bit.Websites.Sales.Client/wwwroot/images/shared/whatsapp-icon.svg diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Api/AppSettings.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Server/AppSettings.cs similarity index 70% rename from src/Websites/Sales/src/Bit.Websites.Sales.Api/AppSettings.cs rename to src/Websites/Sales/src/Bit.Websites.Sales.Server/AppSettings.cs index e728c75a96..b5c8673299 100644 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Api/AppSettings.cs +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Server/AppSettings.cs @@ -1,4 +1,4 @@ -namespace Bit.Websites.Sales.Api; +namespace Bit.Websites.Sales.Server; public class AppSettings { @@ -6,9 +6,6 @@ public class AppSettings public TelegramBotSettings TelegramBotSettings { get; set; } = default!; - public string UserProfileImagesDir { get; set; } = default!; - - public string WebServerAddress { get; set; } = default!; } public class HealthCheckSettings diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Server/Bit.Websites.Sales.Server.csproj b/src/Websites/Sales/src/Bit.Websites.Sales.Server/Bit.Websites.Sales.Server.csproj new file mode 100644 index 0000000000..567f22a1dd --- /dev/null +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Server/Bit.Websites.Sales.Server.csproj @@ -0,0 +1,53 @@ + + + + net8.0 + enable + enable + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + + + + + Always + + + + + + True + True + $([System.String]::Copy('%(Filename)').Replace('.Designer','')).resx + + + PublicResXFileCodeGenerator + %(Filename).Designer.cs + + + + diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Server/Components/App.razor b/src/Websites/Sales/src/Bit.Websites.Sales.Server/Components/App.razor new file mode 100644 index 0000000000..ad2b0d3ef6 --- /dev/null +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Server/Components/App.razor @@ -0,0 +1,75 @@ +@using Bit.Websites.Sales.Client.Services + + + + + + + + + + + +@* *@ + + + + + + + + + + + + + + + +@* *@ + + + + + @if (HttpContext.Request.IsCrawlerClient() is false) + { + + + + } + + + + diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Server/Components/App.razor.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Server/Components/App.razor.cs new file mode 100644 index 0000000000..b5cad7956b --- /dev/null +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Server/Components/App.razor.cs @@ -0,0 +1,23 @@ +using Microsoft.AspNetCore.Components; + +namespace Bit.Websites.Sales.Server.Components; + +[StreamRendering(enabled: true)] +public partial class App +{ + [CascadingParameter] HttpContext HttpContext { get; set; } = default!; + + protected override void OnInitialized() + { + HttpContext.Response.OnStarting(async _ => + { + HttpContext.Response.GetTypedHeaders().CacheControl = new() + { + MaxAge = TimeSpan.FromDays(7), + Public = true + }; + }, null!); + + base.OnInitialized(); + } +} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Server/Components/_Imports.razor b/src/Websites/Sales/src/Bit.Websites.Sales.Server/Components/_Imports.razor new file mode 100644 index 0000000000..03f467e4ec --- /dev/null +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Server/Components/_Imports.razor @@ -0,0 +1,6 @@ +@using System +@using Microsoft.Extensions.Localization +@using Microsoft.AspNetCore.Components.Web +@using Bit.Websites.Sales.Client +@using Bit.Websites.Sales.Client.Shared +@using Bit.BlazorUI \ No newline at end of file diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Server/Controllers/AppControllerBase.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Server/Controllers/AppControllerBase.cs new file mode 100644 index 0000000000..93db754d05 --- /dev/null +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Server/Controllers/AppControllerBase.cs @@ -0,0 +1,6 @@ +namespace Bit.Websites.Sales.Server.Controllers; + +public partial class AppControllerBase : ControllerBase +{ + [AutoInject] protected AppSettings AppSettings = default!; +} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Api/Controllers/ContactUsController.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Server/Controllers/ContactUsController.cs similarity index 85% rename from src/Websites/Sales/src/Bit.Websites.Sales.Api/Controllers/ContactUsController.cs rename to src/Websites/Sales/src/Bit.Websites.Sales.Server/Controllers/ContactUsController.cs index 73919b5e53..8454a2b87d 100644 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Api/Controllers/ContactUsController.cs +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Server/Controllers/ContactUsController.cs @@ -1,7 +1,7 @@ -using Bit.Websites.Sales.Api.Services; +using Bit.Websites.Sales.Server.Services; using Bit.Websites.Sales.Shared.Dtos.ContactUs; -namespace Bit.Websites.Sales.Api.Controllers; +namespace Bit.Websites.Sales.Server.Controllers; [Route("api/[controller]/[action]")] [ApiController] @@ -13,7 +13,6 @@ public partial class ContactUsController : AppControllerBase public async Task SendMessage(ContactUsDto contactUsDto, CancellationToken cancellationToken) { await TelegramBotService.SendContactUsMessage(contactUsDto.Email, contactUsDto.Name, contactUsDto.Information, cancellationToken); - return Ok(); } } diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Extensions/HttpRequestExtensions.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Server/Extensions/HttpRequestExtensions.cs similarity index 53% rename from src/Websites/Careers/src/Bit.Websites.Careers.Web/Extensions/HttpRequestExtensions.cs rename to src/Websites/Sales/src/Bit.Websites.Sales.Server/Extensions/HttpRequestExtensions.cs index 0f62030960..12760a7e32 100644 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Web/Extensions/HttpRequestExtensions.cs +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Server/Extensions/HttpRequestExtensions.cs @@ -4,7 +4,21 @@ namespace Microsoft.AspNetCore.Http; public static class HttpRequestExtensions { - public static bool ShouldRenderStaticMode(this HttpRequest request) + /// + /// https://blog.elmah.io/how-to-get-base-url-in-asp-net-core/ + /// + public static string GetBaseUrl(this HttpRequest req) + { + var uriBuilder = new UriBuilder(req.Scheme, req.Host.Host, req.Host.Port ?? -1); + if (uriBuilder.Uri.IsDefaultPort) + { + uriBuilder.Port = -1; + } + + return uriBuilder.Uri.AbsoluteUri; + } + + public static bool IsCrawlerClient(this HttpRequest request) { var agent = GetLoweredUserAgent(request); @@ -23,6 +37,6 @@ private static string GetLoweredUserAgent(HttpRequest request) if (string.IsNullOrEmpty(userAgent)) return string.Empty; - return userAgent.ToLower(); + return userAgent.ToLowerInvariant(); } } diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Server/Extensions/IServiceCollectionExtensions.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Server/Extensions/IServiceCollectionExtensions.cs new file mode 100644 index 0000000000..ecf0a574ef --- /dev/null +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Server/Extensions/IServiceCollectionExtensions.cs @@ -0,0 +1,72 @@ +using Microsoft.AspNetCore.Components.WebAssembly.Services; +using Microsoft.OpenApi.Models; +using Bit.Websites.Sales.Server; +using Bit.Websites.Sales.Client.Services.HttpMessageHandlers; + +namespace Microsoft.Extensions.DependencyInjection; + +public static class IServiceCollectionExtensions +{ + public static void AddBlazor(this IServiceCollection services, IConfiguration configuration) + { + services.AddScoped(sp => + { + IHttpClientFactory httpClientFactory = sp.GetRequiredService(); + return httpClientFactory.CreateClient("BlazorHttpClient"); + // This registers HttpClient for pre rendering & blazor server only, so to use http client to call 3rd party apis and other use cases, + // either use services.AddHttpClient("NamedHttpClient") or services.AddHttpClient(); + }); + + // In the Pre-Rendering mode, the configured HttpClient will use the access_token provided by the cookie in the request, so the pre-rendered content would be fitting for the current user. + services.AddHttpClient("BlazorHttpClient") + .AddHttpMessageHandler(sp => new RetryDelegatingHandler()) + .AddHttpMessageHandler(sp => new ExceptionDelegatingHandler()) + .ConfigurePrimaryHttpMessageHandler() + .ConfigureHttpClient((sp, httpClient) => + { + Uri.TryCreate(configuration.GetApiServerAddress(), UriKind.RelativeOrAbsolute, out var apiServerAddress); + + if (apiServerAddress!.IsAbsoluteUri is false) + { + apiServerAddress = new Uri($"{sp.GetRequiredService().HttpContext!.Request.GetBaseUrl()}{apiServerAddress}"); + } + + httpClient.BaseAddress = apiServerAddress; + }); + + services.AddScoped(); + + services.AddRazorComponents() + .AddInteractiveServerComponents() + .AddInteractiveWebAssemblyComponents(); + } + + public static void AddSwaggerGen(this IServiceCollection services) + { + services.AddSwaggerGen(options => + { + options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, "Bit.Websites.Sales.Server.xml")); + options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, "Bit.Websites.Sales.Shared.xml")); + }); + } + + public static void AddHealthChecks(this IServiceCollection services, IWebHostEnvironment env, IConfiguration configuration) + { + var appSettings = configuration.GetSection(nameof(AppSettings)).Get()!; + + var healthCheckSettings = appSettings.HealthCheckSettings; + + if (healthCheckSettings.EnableHealthChecks is false) + return; + + services.AddHealthChecksUI(setupSettings: setup => + { + setup.AddHealthCheckEndpoint("WebHealthChecks", env.IsDevelopment() ? "https://localhost:5051/healthz" : "/healthz"); + }).AddInMemoryStorage(); + + var healthChecksBuilder = services.AddHealthChecks() + .AddProcessAllocatedMemoryHealthCheck(maximumMegabytesAllocated: 6 * 1024) + .AddDiskStorageHealthCheck(opt => + opt.AddDrive(Path.GetPathRoot(Directory.GetCurrentDirectory())!, minimumFreeMegabytes: 5 * 1024)); + } +} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Server/Mappers/Readme.md b/src/Websites/Sales/src/Bit.Websites.Sales.Server/Mappers/Readme.md new file mode 100644 index 0000000000..03523e9752 --- /dev/null +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Server/Mappers/Readme.md @@ -0,0 +1,17 @@ +When you have an IQueryable of an Entity or Model classes from EntityFrameworkCore, +you ultimately need to convert it into an IQueryable of DTO classes and return it to the client. +The client can also implement pagination during the API call by sending values for $top, $skip and sort by $orderby in query string. +Ultimately, the query is executed by aspnetcore and the data gets streamed from the database to the client, which is the most optimal case. +For this, you need to write a `Project` for each Entity you intend to return a query of DTO class from. + +You also write a `Map` for when a DTO is sent to the server for create or update api, +so you can convert it to an Entity and save it in the database using ef core. +You also need a Map method to convert DTO to Entity and vice versa. + +You also need a `Patch` method for the update scenario, to perform update operation, first get the Entity from the database with its Id, +then patch the latest changes from the DTO sent by the client, and finally save it. + +These methods (`Project`, `Map` and `Patch`) are gets called in controllers. + +For more information and to learn about customizing the mapping process, visit the website below: +https://mapperly.riok.app/docs/intro/ \ No newline at end of file diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Server/Program.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Server/Program.cs new file mode 100644 index 0000000000..f6c1fd324a --- /dev/null +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Server/Program.cs @@ -0,0 +1,12 @@ +var builder = WebApplication.CreateBuilder(args); + +// We need to load the client app configurations to prerender the app on server side. +builder.Configuration.AddClientConfigurations(); + +Bit.Websites.Sales.Server.Startup.Services.Add(builder.Services, builder.Environment, builder.Configuration); + +var app = builder.Build(); + +Bit.Websites.Sales.Server.Startup.Middlewares.Use(app, builder.Environment, builder.Configuration); + +app.Run(); diff --git a/src/Websites/Careers/src/Bit.Websites.Careers.Api/Properties/launchSettings.json b/src/Websites/Sales/src/Bit.Websites.Sales.Server/Properties/launchSettings.json similarity index 63% rename from src/Websites/Careers/src/Bit.Websites.Careers.Api/Properties/launchSettings.json rename to src/Websites/Sales/src/Bit.Websites.Sales.Server/Properties/launchSettings.json index 281eedd217..f1f9224548 100644 --- a/src/Websites/Careers/src/Bit.Websites.Careers.Api/Properties/launchSettings.json +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Server/Properties/launchSettings.json @@ -1,22 +1,21 @@ { + "$schema": "http://json.schemastore.org/launchsettings.json", "profiles": { - "Bit.Websites.Careers.Api": { + "Bit.Websites.Sales": { "commandName": "Project", "dotnetRunMessages": true, "launchBrowser": true, - "applicationUrl": "https://localhost:5001;http://localhost:5000", - "launchUrl": "swagger", + "applicationUrl": "http://localhost:5050;https://localhost:5051", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } }, - // This configuration allows debugging the Blazor WebAssembly - "Bit.Websites.Careers.Api-BlazorWebAssembly": { + "Bit.Websites.Sales + WASM debugging": { "commandName": "Project", "dotnetRunMessages": true, "launchBrowser": true, "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", - "applicationUrl": "https://localhost:5001;http://localhost:5000", + "applicationUrl": "http://localhost:5050;https://localhost:5051", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Server/Services/ApiExceptionHandler.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Server/Services/ApiExceptionHandler.cs new file mode 100644 index 0000000000..2dcaf3ddc4 --- /dev/null +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Server/Services/ApiExceptionHandler.cs @@ -0,0 +1,50 @@ +using System.Net; +using System.Reflection; +using Microsoft.AspNetCore.Diagnostics; + +namespace Bit.Websites.Sales.Server.Services; + +public partial class ApiExceptionHandler : IExceptionHandler +{ + [AutoInject] private IWebHostEnvironment _webHostEnvironment = default!; + + public async ValueTask TryHandleAsync(HttpContext httpContext, Exception e, CancellationToken cancellationToken) + { + // Using the Request-Id header, one can find the log for server-related exceptions + httpContext.Response.Headers.Append("Request-ID", httpContext.TraceIdentifier); + + var exception = UnWrapException(e); + var knownException = exception as KnownException; + + // The details of all of the exceptions are returned only in dev mode. in any other modes like production, only the details of the known exceptions are returned. + var key = knownException?.Key ?? nameof(UnknownException); + var message = knownException?.Message ?? (_webHostEnvironment.IsDevelopment() ? exception.Message : nameof(UnknownException)); + + var statusCode = (int)(exception is RestException restExp ? restExp.StatusCode : HttpStatusCode.InternalServerError); + + var restExceptionPayload = new RestErrorInfo + { + Key = key, + Message = message, + ExceptionType = knownException?.GetType().FullName ?? typeof(UnknownException).FullName + }; + + if (exception is ResourceValidationException validationException) + { + restExceptionPayload.Payload = validationException.Payload; + } + + httpContext.Response.StatusCode = statusCode; + + await httpContext.Response.WriteAsJsonAsync(restExceptionPayload, AppJsonContext.Default.RestErrorInfo, cancellationToken: cancellationToken); + + return true; + } + + private Exception UnWrapException(Exception exp) + { + return exp is TargetInvocationException && exp.InnerException is not null + ? exp.InnerException + : exp; + } +} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Server/Services/NullAntiforgery.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Server/Services/NullAntiforgery.cs new file mode 100644 index 0000000000..9f69232f6f --- /dev/null +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Server/Services/NullAntiforgery.cs @@ -0,0 +1,22 @@ +using Microsoft.AspNetCore.Antiforgery; + +namespace Bit.Websites.Sales.Server.Services; + +public class NullAntiforgery : IAntiforgery +{ + private const string AntiforgeryTokenFieldName = "__RequestVerificationToken"; + private const string AntiforgeryTokenHeaderName = "RequestVerificationToken"; + + public AntiforgeryTokenSet GetAndStoreTokens(HttpContext httpContext) => new(string.Empty, string.Empty, AntiforgeryTokenFieldName, AntiforgeryTokenHeaderName); + + public AntiforgeryTokenSet GetTokens(HttpContext httpContext) => new(string.Empty, string.Empty, AntiforgeryTokenFieldName, AntiforgeryTokenHeaderName); + + public Task IsRequestValidAsync(HttpContext httpContext) => Task.FromResult(true); + + public void SetCookieTokenAndHeader(HttpContext httpContext) + { + return; + } + + public Task ValidateRequestAsync(HttpContext httpContext) => Task.FromResult(true); +} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Api/Services/TelegramBotApiClient.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Server/Services/TelegramBotApiClient.cs similarity index 97% rename from src/Websites/Sales/src/Bit.Websites.Sales.Api/Services/TelegramBotApiClient.cs rename to src/Websites/Sales/src/Bit.Websites.Sales.Server/Services/TelegramBotApiClient.cs index d794014965..3a7994d8ae 100644 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Api/Services/TelegramBotApiClient.cs +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Server/Services/TelegramBotApiClient.cs @@ -1,7 +1,7 @@ using System.Text; using System.Text.Json; -namespace Bit.Websites.Sales.Api.Services; +namespace Bit.Websites.Sales.Server.Services; public partial class TelegramBotApiClient { diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Api/Services/TelegramBotService.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Server/Services/TelegramBotService.cs similarity index 94% rename from src/Websites/Sales/src/Bit.Websites.Sales.Api/Services/TelegramBotService.cs rename to src/Websites/Sales/src/Bit.Websites.Sales.Server/Services/TelegramBotService.cs index 09be281737..bf8a32a210 100644 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Api/Services/TelegramBotService.cs +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Server/Services/TelegramBotService.cs @@ -1,6 +1,6 @@ using System.Text; -namespace Bit.Websites.Sales.Api.Services; +namespace Bit.Websites.Sales.Server.Services; public partial class TelegramBotService { diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Server/Startup/Middlewares.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Server/Startup/Middlewares.cs new file mode 100644 index 0000000000..b3ffa1f6ca --- /dev/null +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Server/Startup/Middlewares.cs @@ -0,0 +1,85 @@ +using System.Reflection; +using HealthChecks.UI.Client; +using Microsoft.AspNetCore.Diagnostics.HealthChecks; +using Microsoft.AspNetCore.Http.Extensions; +using Microsoft.Net.Http.Headers; +using Bit.Websites.Sales.Server.Components; + +namespace Bit.Websites.Sales.Server.Startup; + +public class Middlewares +{ + public static void Use(WebApplication app, IHostEnvironment env, IConfiguration configuration) + { + app.UseForwardedHeaders(); + + if (env.IsDevelopment()) + { + app.UseWebAssemblyDebugging(); + } + else + { + app.UseHttpsRedirection(); + app.UseResponseCompression(); + } + + app.UseStatusCodePages(options: new() + { + HandleAsync = async (statusCodeContext) => + { + var httpContext = statusCodeContext.HttpContext; + + if (httpContext.Response.StatusCode is 404) + { + httpContext.Response.Redirect($"not-found?url={httpContext.Request.GetEncodedPathAndQuery()}"); + } + else if (httpContext.Response.StatusCode is 401) + { + httpContext.Response.Redirect($"not-authorized?redirectUrl={httpContext.Request.GetEncodedPathAndQuery()}"); + } + } + }); + + app.UseStaticFiles(new StaticFileOptions + { + OnPrepareResponse = ctx => + { + // https://bitplatform.dev/templates/cache-mechanism + ctx.Context.Response.GetTypedHeaders().CacheControl = new CacheControlHeaderValue() + { + MaxAge = TimeSpan.FromDays(7), + Public = true + }; + } + }); + + app.UseResponseCaching(); + app.UseAntiforgery(); + + app.UseExceptionHandler("/", createScopeForErrors: true); + app.UseSwagger(); + + app.UseSwaggerUI(); + + app.MapControllers(); + + var appSettings = configuration.GetSection(nameof(AppSettings)).Get()!; + + var healthCheckSettings = appSettings.HealthCheckSettings; + + if (healthCheckSettings.EnableHealthChecks) + { + app.MapHealthChecks("/healthz", new HealthCheckOptions + { + ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse + }); + + app.MapHealthChecksUI(); + } + + app.MapRazorComponents() + .AddInteractiveServerRenderMode() + .AddInteractiveWebAssemblyRenderMode() + .AddAdditionalAssemblies(Assembly.Load("Bit.Websites.Sales.Client")); + } +} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Server/Startup/Services.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Server/Startup/Services.cs new file mode 100644 index 0000000000..2a0be13de5 --- /dev/null +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Server/Startup/Services.cs @@ -0,0 +1,60 @@ +using System.IO.Compression; +using Microsoft.AspNetCore.HttpOverrides; +using Microsoft.AspNetCore.ResponseCompression; +using Bit.Websites.Sales.Server.Services; +using Microsoft.AspNetCore.Antiforgery; + +namespace Bit.Websites.Sales.Server.Startup; + +public static class Services +{ + public static void Add(IServiceCollection services, IWebHostEnvironment env, IConfiguration configuration) + { + // Services being registered here can get injected into controllers and services in Api project. + + var appSettings = configuration.GetSection(nameof(AppSettings)).Get()!; + + services.AddTransient(); + services.AddHttpClient(); + services.AddScoped(); + + services.AddClientSharedServices(); + + services.AddExceptionHandler(); + + services.AddBlazor(configuration); + + services + .AddControllers(); + + services.Configure(options => + { + options.ForwardedHeaders = ForwardedHeaders.All; + options.ForwardedHostHeaderName = "X-Host"; + }); + + services.AddResponseCaching(); + + services.AddHttpContextAccessor(); + + services.AddResponseCompression(opts => + { + opts.EnableForHttps = true; + opts.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(["application/octet-stream"]).ToArray(); + opts.Providers.Add(); + opts.Providers.Add(); + }) + .Configure(opt => opt.Level = CompressionLevel.Fastest) + .Configure(opt => opt.Level = CompressionLevel.Fastest); + + services.Configure(configuration.GetSection(nameof(AppSettings))); + + services.AddScoped(sp => sp.GetRequiredService>().Value); + + services.AddEndpointsApiExplorer(); + + services.AddSwaggerGen(); + + services.AddHealthChecks(env, configuration); + } +} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Server/appsettings.Development.json b/src/Websites/Sales/src/Bit.Websites.Sales.Server/appsettings.Development.json new file mode 100644 index 0000000000..f3f302cced --- /dev/null +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Server/appsettings.Development.json @@ -0,0 +1,5 @@ +{ + "AppSettings": { + + } +} \ No newline at end of file diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Api/appsettings.json b/src/Websites/Sales/src/Bit.Websites.Sales.Server/appsettings.json similarity index 100% rename from src/Websites/Sales/src/Bit.Websites.Sales.Api/appsettings.json rename to src/Websites/Sales/src/Bit.Websites.Sales.Server/appsettings.json diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Attributes/DtoResourceTypeAttribute.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Attributes/DtoResourceTypeAttribute.cs deleted file mode 100644 index 4b9c276a23..0000000000 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Attributes/DtoResourceTypeAttribute.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Bit.Websites.Sales.Shared.Attributes; - -/// -/// Gets or sets the resource type to use for error message & localizations lookups. -/// -public class DtoResourceTypeAttribute : Attribute -{ - public Type ResourceType { get; } - - public DtoResourceTypeAttribute(Type resourceType) - { - ResourceType = resourceType ?? throw new ArgumentNullException(nameof(resourceType)); - } -} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Bit.Websites.Sales.Shared.csproj b/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Bit.Websites.Sales.Shared.csproj index b3da70abe9..96dbf45ddf 100644 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Bit.Websites.Sales.Shared.csproj +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Bit.Websites.Sales.Shared.csproj @@ -1,6 +1,8 @@  + net8.0 + en-US @@ -13,14 +15,15 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + + compile; build; native; contentfiles; analyzers; buildtransitive + - diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Dtos/AppJsonContext.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Dtos/AppJsonContext.cs index c02854cba1..297e741cff 100644 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Dtos/AppJsonContext.cs +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Dtos/AppJsonContext.cs @@ -6,6 +6,7 @@ namespace Bit.Websites.Sales.Shared.Dtos; /// https://devblogs.microsoft.com/dotnet/try-the-new-system-text-json-source-generator/ ///
[JsonSourceGenerationOptions(PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase)] +[JsonSerializable(typeof(Dictionary))] [JsonSerializable(typeof(RestErrorInfo))] [JsonSerializable(typeof(ContactUsDto))] public partial class AppJsonContext : JsonSerializerContext diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Exceptions/BadRequestException.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Exceptions/BadRequestException.cs index fd8420ebd2..b65cec41f0 100644 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Exceptions/BadRequestException.cs +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Exceptions/BadRequestException.cs @@ -5,7 +5,7 @@ namespace Bit.Websites.Sales.Shared.Exceptions; public class BadRequestException : RestException { public BadRequestException() - : base(nameof(AppStrings.BadRequestException)) + : base(nameof(BadRequestException)) { } @@ -19,15 +19,5 @@ public BadRequestException(string message, Exception? innerException) { } - public BadRequestException(LocalizedString message) - : base(message) - { - } - - public BadRequestException(LocalizedString message, Exception? innerException) - : base(message, innerException) - { - } - public override HttpStatusCode StatusCode => HttpStatusCode.BadRequest; } diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Exceptions/ConflictException.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Exceptions/ConflictException.cs index 283ec2f58c..743699ffe5 100644 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Exceptions/ConflictException.cs +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Exceptions/ConflictException.cs @@ -5,7 +5,7 @@ namespace Bit.Websites.Sales.Shared.Exceptions; public class ConflictException : RestException { public ConflictException() - : this(nameof(AppStrings.ConflicException)) + : this(nameof(ConflictException)) { } @@ -19,15 +19,5 @@ public ConflictException(string message, Exception? innerException) { } - public ConflictException(LocalizedString message) - : base(message) - { - } - - public ConflictException(LocalizedString message, Exception? innerException) - : base(message, innerException) - { - } - public override HttpStatusCode StatusCode => HttpStatusCode.Conflict; } diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Exceptions/DomainLogicException.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Exceptions/DomainLogicException.cs index 671b96fbff..d448e441c9 100644 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Exceptions/DomainLogicException.cs +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Exceptions/DomainLogicException.cs @@ -11,14 +11,4 @@ public DomainLogicException(string message, Exception? innerException) : base(message, innerException) { } - - public DomainLogicException(LocalizedString message) - : base(message) - { - } - - public DomainLogicException(LocalizedString message, Exception? innerException) - : base(message, innerException) - { - } } diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Exceptions/ErrorResourcePayload.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Exceptions/ErrorResourcePayload.cs index 77a75ea728..5415664ac3 100644 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Exceptions/ErrorResourcePayload.cs +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Exceptions/ErrorResourcePayload.cs @@ -4,14 +4,14 @@ public class ErrorResourcePayload { public string? ResourceTypeName { get; set; } = "*"; - public List Details { get; set; } = new(); + public List Details { get; set; } = []; } public class PropertyErrorResourceCollection { public string? Name { get; set; } = "*"; - public List Errors { get; set; } = new(); + public List Errors { get; set; } = []; } public class ErrorResource diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Exceptions/ForbiddenException.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Exceptions/ForbiddenException.cs deleted file mode 100644 index c27828c0c6..0000000000 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Exceptions/ForbiddenException.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Net; - -namespace Bit.Websites.Sales.Shared.Exceptions; - -public class ForbiddenException : RestException -{ - public ForbiddenException() - : base(nameof(AppStrings.ForbiddenException)) - { - } - - public ForbiddenException(string message) - : base(message) - { - } - - public ForbiddenException(string message, Exception? innerException) - : base(message, innerException) - { - } - - public ForbiddenException(LocalizedString message) - : base(message) - { - } - - public ForbiddenException(LocalizedString message, Exception? innerException) - : base(message, innerException) - { - } - - public override HttpStatusCode StatusCode => HttpStatusCode.Forbidden; -} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Exceptions/KnownException.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Exceptions/KnownException.cs index bc608e358b..adfa9a8d8c 100644 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Exceptions/KnownException.cs +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Exceptions/KnownException.cs @@ -14,17 +14,5 @@ public KnownException(string message, Exception? innerException) Key = message; } - public KnownException(LocalizedString message) - : base(message.Value) - { - Key = message.Name; - } - - public KnownException(LocalizedString message, Exception? innerException) - : base(message.Value, innerException) - { - Key = message.Name; - } - public string? Key { get; set; } } diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Exceptions/ResourceNotFoundException.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Exceptions/ResourceNotFoundException.cs index 34cbaa971b..54a9e7aec7 100644 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Exceptions/ResourceNotFoundException.cs +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Exceptions/ResourceNotFoundException.cs @@ -5,7 +5,7 @@ namespace Bit.Websites.Sales.Shared.Exceptions; public class ResourceNotFoundException : RestException { public ResourceNotFoundException() - : base(nameof(AppStrings.ResourceNotFoundException)) + : base(nameof(ResourceNotFoundException)) { } @@ -19,15 +19,5 @@ public ResourceNotFoundException(string message, Exception? innerException) { } - public ResourceNotFoundException(LocalizedString message) - : base(message) - { - } - - public ResourceNotFoundException(LocalizedString message, Exception? innerException) - : base(message, innerException) - { - } - public override HttpStatusCode StatusCode => HttpStatusCode.NotFound; } diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Exceptions/ResourceValidationException.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Exceptions/ResourceValidationException.cs index 0ac02b4e26..8023cb3555 100644 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Exceptions/ResourceValidationException.cs +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Exceptions/ResourceValidationException.cs @@ -4,44 +4,8 @@ namespace Bit.Websites.Sales.Shared.Exceptions; public class ResourceValidationException : RestException { - public ResourceValidationException(params LocalizedString[] errorMessages) - : this(new[] { ("*", errorMessages) }) - { - - } - - public ResourceValidationException((string propName, LocalizedString[] errorMessages)[] details) - : this("*", details) - { - - } - - public ResourceValidationException(Type resourceType, (string propName, LocalizedString[] errorMessages)[] details) - : this(resourceType.FullName!, details) - { - - } - - public ResourceValidationException(string resourceTypeName, (string propName, LocalizedString[] errorMessages)[] details) - : this(new ErrorResourcePayload() - { - ResourceTypeName = resourceTypeName, - Details = details.Select(propErrors => new PropertyErrorResourceCollection - { - Name = propErrors.propName, - Errors = propErrors.errorMessages.Select(e => new ErrorResource() - { - Key = e.Name, - Message = e.Value - }).ToList() - }).ToList() - }) - { - - } - public ResourceValidationException(ErrorResourcePayload payload) - : this(message: nameof(AppStrings.ResourceValidationException), payload) + : this(message: nameof(ResourceValidationException), payload) { } diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Exceptions/RestErrorInfo.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Exceptions/RestErrorInfo.cs index e1d20472a0..5f8ba0dffb 100644 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Exceptions/RestErrorInfo.cs +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Exceptions/RestErrorInfo.cs @@ -8,5 +8,5 @@ public class RestErrorInfo public string? Message { get; set; } - public ErrorResourcePayload Payload { get; set; } = new(); + public ErrorResourcePayload? Payload { get; set; } } diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Exceptions/RestException.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Exceptions/RestException.cs index 64b7fe669f..1856e29d59 100644 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Exceptions/RestException.cs +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Exceptions/RestException.cs @@ -5,7 +5,7 @@ namespace Bit.Websites.Sales.Shared.Exceptions; public class RestException : KnownException { public RestException() - : base(nameof(AppStrings.RestException)) + : base(nameof(RestException)) { } @@ -19,15 +19,5 @@ public RestException(string message, Exception? innerException) { } - public RestException(LocalizedString message) - : base(message) - { - } - - public RestException(LocalizedString message, Exception? innerException) - : base(message, innerException) - { - } - public virtual HttpStatusCode StatusCode => HttpStatusCode.InternalServerError; } diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Exceptions/ServerConnectionException.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Exceptions/ServerConnectionException.cs new file mode 100644 index 0000000000..58baeffeaa --- /dev/null +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Exceptions/ServerConnectionException.cs @@ -0,0 +1,18 @@ +namespace Bit.Websites.Sales.Shared.Exceptions; +public class ServerConnectionException : UnknownException +{ + public ServerConnectionException() + : base(nameof(ServerConnectionException)) + { + } + + public ServerConnectionException(string message) + : base(message) + { + } + + public ServerConnectionException(string message, Exception innerException) + : base(message, innerException) + { + } +} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Exceptions/TooManyRequestsExceptions.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Exceptions/TooManyRequestsExceptions.cs index 183d33a05e..a19a0f5442 100644 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Exceptions/TooManyRequestsExceptions.cs +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Exceptions/TooManyRequestsExceptions.cs @@ -5,7 +5,7 @@ namespace Bit.Websites.Sales.Shared.Exceptions; public class TooManyRequestsExceptions : RestException { public TooManyRequestsExceptions() - : base(nameof(AppStrings.TooManyRequestsExceptions)) + : base(nameof(TooManyRequestsExceptions)) { } @@ -19,15 +19,5 @@ public TooManyRequestsExceptions(string message, Exception? innerException) { } - public TooManyRequestsExceptions(LocalizedString message) - : base(message) - { - } - - public TooManyRequestsExceptions(LocalizedString message, Exception? innerException) - : base(message, innerException) - { - } - public override HttpStatusCode StatusCode => HttpStatusCode.TooManyRequests; } diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Exceptions/UnauthorizedException.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Exceptions/UnauthorizedException.cs deleted file mode 100644 index 78609f9344..0000000000 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Exceptions/UnauthorizedException.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System.Net; - -namespace Bit.Websites.Sales.Shared.Exceptions; - -public class UnauthorizedException : RestException -{ - public UnauthorizedException() - : base(nameof(AppStrings.UnauthorizedException)) - { - } - - public UnauthorizedException(string message) - : base(message) - { - } - - public UnauthorizedException(string message, Exception? innerException) - : base(message, innerException) - { - } - - public UnauthorizedException(LocalizedString message) - : base(message) - { - } - - public UnauthorizedException(LocalizedString message, Exception? innerException) - : base(message, innerException) - { - } - - public override HttpStatusCode StatusCode => HttpStatusCode.Unauthorized; -} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Exceptions/UnknownException.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Exceptions/UnknownException.cs index 2e59e4af12..e8f5dc685a 100644 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Exceptions/UnknownException.cs +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Exceptions/UnknownException.cs @@ -3,7 +3,7 @@ public class UnknownException : Exception { public UnknownException() - : base(nameof(AppStrings.UnknownException)) + : base(nameof(UnknownException)) { } @@ -17,4 +17,3 @@ public UnknownException(string message, Exception innerException) { } } - diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Extensions/ClaimsPrincipalExtensions.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Extensions/ClaimsPrincipalExtensions.cs deleted file mode 100644 index 9929bc0776..0000000000 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Extensions/ClaimsPrincipalExtensions.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace System.Security.Claims; - -public static class ClaimsPrincipalExtensions -{ - public static int GetUserId(this ClaimsPrincipal claimsPrincipal) - { - return int.Parse(claimsPrincipal.FindFirst(ClaimTypes.NameIdentifier)!.Value); - } - - public static string GetUserName(this ClaimsPrincipal claimsPrincipal) - { - return claimsPrincipal.FindFirst(ClaimTypes.Name)!.Value; - } -} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Extensions/IServiceCollectionExtensions.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Extensions/IServiceCollectionExtensions.cs index a050daaa06..ab66557fed 100644 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Extensions/IServiceCollectionExtensions.cs +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Extensions/IServiceCollectionExtensions.cs @@ -4,12 +4,12 @@ namespace Microsoft.Extensions.DependencyInjection; public static class IServiceCollectionExtensions { - public static void AddSharedServices(this IServiceCollection services) + public static IServiceCollection AddSharedServices(this IServiceCollection services) { - // Services being registered here can get injected everywhere (Api & Web) - - services.AddLocalization(); + // Services being registered here can get injected everywhere (Api, Web, Android, iOS, Windows, macOS and Linux) services.AddSingleton(); + + return services; } } diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Extensions/LinqExtensions.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Extensions/LinqExtensions.cs new file mode 100644 index 0000000000..718221b8fc --- /dev/null +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Extensions/LinqExtensions.cs @@ -0,0 +1,39 @@ +using System.Linq.Expressions; + +namespace System.Collections.Generic; + +public static class LinqExtensions +{ + /// + /// https://extensionmethod.net/csharp/ienumerable-t/whereif + /// + public static IQueryable WhereIf(this IQueryable query, bool predicate, Expression> itemPredicate) + { + return predicate ? query.Where(itemPredicate) : query; + } + + public static IQueryable OrderByIf(this IQueryable query, bool predicate, Expression> keySelector) + { + return predicate ? query.OrderBy(keySelector) : query; + } + + public static IQueryable OrderByDescendingIf(this IQueryable query, bool predicate, Expression> keySelector) + { + return predicate ? query.OrderByDescending(keySelector) : query; + } + + public static IEnumerable WhereIf(this IEnumerable source, bool predicate, Func itemPredicate) + { + return predicate ? source.Where(itemPredicate) : source; + } + + public static IEnumerable OrderByIf(this IEnumerable source, bool predicate, Func keySelector) + { + return predicate ? source.OrderBy(keySelector) : source; + } + + public static IEnumerable OrderByDescendingIf(this IEnumerable source, bool predicate, Func keySelector) + { + return predicate ? source.OrderByDescending(keySelector) : source; + } +} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Infra/BlazorMode.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Infra/BlazorMode.cs deleted file mode 100644 index eacfbae650..0000000000 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Infra/BlazorMode.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Bit.Websites.Sales.Shared.Infra; - -public enum BlazorMode -{ - BlazorServer = 0, - BlazorWebAssembly = 1 -} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Infra/BlazorModeDetector.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Infra/BlazorModeDetector.cs deleted file mode 100644 index 191d0b82ec..0000000000 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Infra/BlazorModeDetector.cs +++ /dev/null @@ -1,31 +0,0 @@ -namespace Bit.Websites.Sales.Shared.Infra; - -/// -/// https://bitplatform.dev/templates/hosting-models -/// -public class BlazorModeDetector -{ - public static BlazorModeDetector Current { get; set; } = new BlazorModeDetector(); - - public virtual bool IsBlazorServer() - { - return Mode == BlazorMode.BlazorServer; - } - - public virtual bool IsBlazorWebAssembly() - { - return Mode == BlazorMode.BlazorWebAssembly; - } - - public virtual BlazorMode Mode - { - get - { -#if BlazorWebAssembly - return BlazorMode.BlazorWebAssembly; -#else - return BlazorMode.BlazorServer; -#endif - } - } -} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Infra/CultureInfoManager.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Infra/CultureInfoManager.cs deleted file mode 100644 index 75692962c3..0000000000 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Infra/CultureInfoManager.cs +++ /dev/null @@ -1,101 +0,0 @@ -using System.Reflection; - -namespace Bit.Websites.Sales.Shared.Infra; -public class CultureInfoManager -{ - public static (string name, string code) DefaultCulture { get; } = ("English", "en-US"); - - public static (string name, string code)[] SupportedCultures { get; } = new (string name, string code)[] - { - ("English US", "en-US"), - // ("فارسی", "fa-IR"), // To add more languages, you've to provide resx files. You might also put some efforts to change your app flow direction based on CultureInfo.CurrentUICulture.TextInfo.IsRightToLeft - }; - - public static CultureInfo CreateCultureInfo(string cultureInfoId) - { - var cultureInfo = OperatingSystem.IsBrowser() ? CultureInfo.CreateSpecificCulture(cultureInfoId) : new CultureInfo(cultureInfoId); - - if (cultureInfoId == "fa-IR") - { - CustomizeCultureInfoForFaCulture(cultureInfo); - } - - return cultureInfo; - } - - public static void SetCurrentCulture(string? cultureInfoCookie) - { - var currentCulture = GetCurrentCulture(cultureInfoCookie); - - var cultureInfo = CreateCultureInfo(currentCulture); - - CultureInfo.CurrentCulture = CultureInfo.CurrentUICulture = CultureInfo.DefaultThreadCurrentCulture = CultureInfo.DefaultThreadCurrentUICulture = Thread.CurrentThread.CurrentCulture = Thread.CurrentThread.CurrentUICulture = cultureInfo; - } - - public static string GetCurrentCulture(string? preferredCultureCookie) - { - string culture = CultureInfo.CurrentUICulture.Name; - if (preferredCultureCookie is not null) - { - culture = preferredCultureCookie[(preferredCultureCookie.IndexOf("|uic=") + 5)..]; - } - if (SupportedCultures.Any(sc => sc.code == culture) is false) - { - culture = DefaultCulture.code; - } - return culture; - } - - /// - /// This is an example to demonstrate the way you can customize application culture - /// - public static CultureInfo CustomizeCultureInfoForFaCulture(CultureInfo cultureInfo) - { - cultureInfo.DateTimeFormat.MonthNames = new[] - { - "فروردین", "اردیبهشت", "خرداد", "تیر", "مرداد", "شهریور", "مهر", "آبان", "آذر", "دی", "بهمن", "اسفند", "" - }; - - cultureInfo.DateTimeFormat.AbbreviatedMonthNames = new[] - { - "فرور", "ارد", "خرد", "تیر", "مرد", "شهر", "مهر", "آبا", "آذر", "دی", "بهم", "اسف", "" - }; - - cultureInfo.DateTimeFormat.MonthGenitiveNames = cultureInfo.DateTimeFormat.MonthNames; - cultureInfo.DateTimeFormat.AbbreviatedMonthGenitiveNames = cultureInfo.DateTimeFormat.AbbreviatedMonthNames; - cultureInfo.DateTimeFormat.DayNames = new[] - { - "یکشنبه", "دوشنبه", "ﺳﻪشنبه", "چهارشنبه", "پنجشنبه", "جمعه", "شنبه" - }; - - cultureInfo.DateTimeFormat.AbbreviatedDayNames = new[] - { - "ی", "د", "س", "چ", "پ", "ج", "ش" - }; - - cultureInfo.DateTimeFormat.ShortestDayNames = new[] - { - "ی", "د", "س", "چ", "پ", "ج", "ش" - }; - - cultureInfo.DateTimeFormat.AMDesignator = "ق.ظ"; - cultureInfo.DateTimeFormat.PMDesignator = "ب.ظ"; - cultureInfo.DateTimeFormat.ShortDatePattern = "yyyy/MM/dd"; - cultureInfo.DateTimeFormat.FirstDayOfWeek = DayOfWeek.Saturday; - - var cultureData = _cultureDataField.GetValue(cultureInfo.TextInfo); - - _iReadingLayoutField.SetValue(cultureData, 1 /*rtl*/); // this affects cultureInfo.TextInfo.IsRightToLeft - - if (cultureInfo.DateTimeFormat.Calendar is not PersianCalendar) - { - cultureInfo.DateTimeFormat.Calendar = new PersianCalendar(); - } - - return cultureInfo; - } - - private static readonly FieldInfo _cultureDataField = typeof(TextInfo).GetField("_cultureData", BindingFlags.NonPublic | BindingFlags.Instance)!; - - private static readonly FieldInfo _iReadingLayoutField = Type.GetType("System.Globalization.CultureData, System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e")!.GetField("_iReadingLayout", BindingFlags.NonPublic | BindingFlags.Instance)!; -} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Infra/WebAppDeploymentType.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Infra/WebAppDeploymentType.cs deleted file mode 100644 index 462e31ccdd..0000000000 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Infra/WebAppDeploymentType.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Bit.Websites.Sales.Shared.Infra; - -public enum WebAppDeploymentType -{ - Ssr, - Static -} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Infra/WebAppDeploymentTypeDetector.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Infra/WebAppDeploymentTypeDetector.cs deleted file mode 100644 index 312f2b90cd..0000000000 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Infra/WebAppDeploymentTypeDetector.cs +++ /dev/null @@ -1,31 +0,0 @@ -namespace Bit.Websites.Sales.Shared.Infra; - -/// -/// https://bitplatform.dev/templates/hosting-models -/// -public class WebAppDeploymentTypeDetector -{ - public static WebAppDeploymentTypeDetector Current { get; set; } = new WebAppDeploymentTypeDetector(); - - public virtual bool IsStatic() - { - return Mode == WebAppDeploymentType.Static; - } - - public virtual bool IsSsr() - { - return Mode == WebAppDeploymentType.Ssr; - } - - public virtual WebAppDeploymentType Mode - { - get - { -#if SSR - return WebAppDeploymentType.Ssr; -#else - return WebAppDeploymentType.Static; -#endif - } - } -} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Mapper.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Mapper.cs new file mode 100644 index 0000000000..e406cc2365 --- /dev/null +++ b/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Mapper.cs @@ -0,0 +1,17 @@ +using Riok.Mapperly.Abstractions; + +namespace Bit.Websites.Sales.Shared; + +/// +/// Patching methods help you patch the DTO you have received from the server (for example, after calling an Update api) +/// onto the DTO you have bound to the UI. This way, the UI gets updated with the latest saved changes, +/// and there's no need to re-fetch that specific data from the server. +/// For complete end to end sample you can check EditProfilePage.razor.cs +/// You can add as many as Patch methods you want for other DTO classes here. +/// For more information and to learn about customizing the mapping process, visit the website below: +/// https://mapperly.riok.app/docs/intro/ +/// +[Mapper(UseDeepCloning = true)] +public static partial class Mapper +{ +} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Resources/AppStrings.Designer.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Resources/AppStrings.Designer.cs deleted file mode 100644 index ba7cefdbde..0000000000 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Resources/AppStrings.Designer.cs +++ /dev/null @@ -1,1585 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.42000 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace Bit.Websites.Sales.Shared.Resources { - using System; - - - /// - /// 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.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - public class AppStrings { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal AppStrings() { - } - - /// - /// 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("Bit.Websites.Sales.Shared.Resources.AppStrings", typeof(AppStrings).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; - } - } - - /// - /// Looks up a localized string similar to Active. - /// - public static string Active { - get { - return ResourceManager.GetString("Active", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Add. - /// - public static string Add { - get { - return ResourceManager.GetString("Add", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to All. - /// - public static string All { - get { - return ResourceManager.GetString("All", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Alphabetical. - /// - public static string Alphabetical { - get { - return ResourceManager.GetString("Alphabetical", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Already have an account?. - /// - public static string AlreadyHaveAccountMessage { - get { - return ResourceManager.GetString("AlreadyHaveAccountMessage", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The argument '{0}' cannot be null, empty or contain only whitespace.. - /// - public static string ArgumentIsNullOrWhitespace { - get { - return ResourceManager.GetString("ArgumentIsNullOrWhitespace", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The associated metadata type for type '{0}' contains the following unknown properties or fields: {1}. Please make sure that the names of these members match the names of the properties on the main type.. - /// - public static string AssociatedMetadataTypeTypeDescriptor_MetadataTypeContainsUnknownProperties { - get { - return ResourceManager.GetString("AssociatedMetadataTypeTypeDescriptor_MetadataTypeContainsUnknownProperties", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The type '{0}' does not contain a public property named '{1}'.. - /// - public static string AttributeStore_Unknown_Property { - get { - return ResourceManager.GetString("AttributeStore_Unknown_Property", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Invalid request. - /// - public static string BadRequestException { - get { - return ResourceManager.GetString("BadRequestException", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Birthdate. - /// - public static string BirthDate { - get { - return ResourceManager.GetString("BirthDate", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Cancel. - /// - public static string Cancel { - get { - return ResourceManager.GetString("Cancel", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Check your Spam/Junk, if you could not find it in the Inbox.. - /// - public static string CheckSpamMailMessage { - get { - return ResourceManager.GetString("CheckSpamMailMessage", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The property {0}.{1} could not be found.. - /// - public static string Common_PropertyNotFound { - get { - return ResourceManager.GetString("Common_PropertyNotFound", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Could not find a property named {0}.. - /// - public static string CompareAttribute_UnknownProperty { - get { - return ResourceManager.GetString("CompareAttribute_UnknownProperty", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to '{0}' and '{1}' do not match.. - /// - public static string CompareAttribute_ValidationError { - get { - return ResourceManager.GetString("CompareAttribute_ValidationError", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Completed. - /// - public static string Completed { - get { - return ResourceManager.GetString("Completed", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Optimistic concurrency failure, object has been modified.. - /// - public static string ConcurrencyFailure { - get { - return ResourceManager.GetString("ConcurrencyFailure", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to We have sent a confirmation link to your email address. - ///Please confirm your email by clicking on the link.. - /// - public static string ConfirmEmailMessage { - get { - return ResourceManager.GetString("ConfirmEmailMessage", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Confirm Your Email Address. - /// - public static string ConfirmEmailTitle { - get { - return ResourceManager.GetString("ConfirmEmailTitle", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Confirm New Password. - /// - public static string ConfirmNewPassword { - get { - return ResourceManager.GetString("ConfirmNewPassword", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Request could not be processed because of conflict in the request. - /// - public static string ConflicException { - get { - return ResourceManager.GetString("ConflicException", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The {0} field is not a valid credit card number.. - /// - public static string CreditCardAttribute_Invalid { - get { - return ResourceManager.GetString("CreditCardAttribute_Invalid", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The CustomValidationAttribute method '{0}' in type '{1}' must return System.ComponentModel.DataAnnotations.ValidationResult. Use System.ComponentModel.DataAnnotations.ValidationResult.Success to represent success.. - /// - public static string CustomValidationAttribute_Method_Must_Return_ValidationResult { - get { - return ResourceManager.GetString("CustomValidationAttribute_Method_Must_Return_ValidationResult", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The CustomValidationAttribute method '{0}' does not exist in type '{1}' or is not public and static.. - /// - public static string CustomValidationAttribute_Method_Not_Found { - get { - return ResourceManager.GetString("CustomValidationAttribute_Method_Not_Found", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The CustomValidationAttribute.Method was not specified.. - /// - public static string CustomValidationAttribute_Method_Required { - get { - return ResourceManager.GetString("CustomValidationAttribute_Method_Required", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The CustomValidationAttribute method '{0}' in type '{1}' must match the expected signature: public static ValidationResult {0}(object value, ValidationContext context). The value can be strongly typed. The ValidationContext parameter is optional.. - /// - public static string CustomValidationAttribute_Method_Signature { - get { - return ResourceManager.GetString("CustomValidationAttribute_Method_Signature", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Could not convert the value of type '{0}' to '{1}' as expected by method {2}.{3}.. - /// - public static string CustomValidationAttribute_Type_Conversion_Failed { - get { - return ResourceManager.GetString("CustomValidationAttribute_Type_Conversion_Failed", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The custom validation type '{0}' must be public.. - /// - public static string CustomValidationAttribute_Type_Must_Be_Public { - get { - return ResourceManager.GetString("CustomValidationAttribute_Type_Must_Be_Public", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to {0} is not valid.. - /// - public static string CustomValidationAttribute_ValidationError { - get { - return ResourceManager.GetString("CustomValidationAttribute_ValidationError", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The CustomValidationAttribute.ValidatorType was not specified.. - /// - public static string CustomValidationAttribute_ValidatorType_Required { - get { - return ResourceManager.GetString("CustomValidationAttribute_ValidatorType_Required", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The custom DataType string cannot be null or empty.. - /// - public static string DataTypeAttribute_EmptyDataTypeString { - get { - return ResourceManager.GetString("DataTypeAttribute_EmptyDataTypeString", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Date. - /// - public static string Date { - get { - return ResourceManager.GetString("Date", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The {0} property has not been set. Use the {1} method to get the value.. - /// - public static string DisplayAttribute_PropertyNotSet { - get { - return ResourceManager.GetString("DisplayAttribute_PropertyNotSet", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Don’t have an account?. - /// - public static string DontHaveAccountMessage { - get { - return ResourceManager.GetString("DontHaveAccountMessage", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Email '{0}' is already taken.. - /// - public static string DuplicateEmail { - get { - return ResourceManager.GetString("DuplicateEmail", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Role name '{0}' is already taken.. - /// - public static string DuplicateRoleName { - get { - return ResourceManager.GetString("DuplicateRoleName", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Username '{0}' is already taken.. - /// - public static string DuplicateUserName { - get { - return ResourceManager.GetString("DuplicateUserName", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Edit. - /// - public static string Edit { - get { - return ResourceManager.GetString("Edit", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Edit profile. - /// - public static string EditProfileTitle { - get { - return ResourceManager.GetString("EditProfileTitle", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Email. - /// - public static string Email { - get { - return ResourceManager.GetString("Email", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The {0} field is not a valid e-mail address.. - /// - public static string EmailAddressAttribute_ValidationError { - get { - return ResourceManager.GetString("EmailAddressAttribute_ValidationError", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Your email is already confirmed.. - /// - public static string EmailAlreadyConfirmed { - get { - return ResourceManager.GetString("EmailAlreadyConfirmed", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Email Confirmation Failed!. - /// - public static string EmailConfirmationFailedMessage { - get { - return ResourceManager.GetString("EmailConfirmationFailedMessage", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Email Confirmation. - /// - public static string EmailConfirmationTitle { - get { - return ResourceManager.GetString("EmailConfirmationTitle", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Email Confirmed Successfully!. - /// - public static string EmailConfirmedSuccessfullyMessage { - get { - return ResourceManager.GetString("EmailConfirmedSuccessfullyMessage", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Email '{0}' is not confirmed.. - /// - public static string EmailNotConfirmed { - get { - return ResourceManager.GetString("EmailNotConfirmed", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The type provided for EnumDataTypeAttribute cannot be null.. - /// - public static string EnumDataTypeAttribute_TypeCannotBeNull { - get { - return ResourceManager.GetString("EnumDataTypeAttribute_TypeCannotBeNull", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The type '{0}' needs to represent an enumeration type.. - /// - public static string EnumDataTypeAttribute_TypeNeedsToBeAnEnum { - get { - return ResourceManager.GetString("EnumDataTypeAttribute_TypeNeedsToBeAnEnum", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Error. - /// - public static string Error { - get { - return ResourceManager.GetString("Error", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The {0} field only accepts files with the following extensions: {1}. - /// - public static string FileExtensionsAttribute_Invalid { - get { - return ResourceManager.GetString("FileExtensionsAttribute_Invalid", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to An error occurred while removing file. - /// - public static string FileRemoveFailed { - get { - return ResourceManager.GetString("FileRemoveFailed", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to An error occurred while uploading file. - /// - public static string FileUploadFailed { - get { - return ResourceManager.GetString("FileUploadFailed", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Access to the requested resource is forbidden. - /// - public static string ForbiddenException { - get { - return ResourceManager.GetString("ForbiddenException", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Please enter the email address you have been signed up with so we can send a reset password link to your email address.. - /// - public static string ForgetPasswordMessage { - get { - return ResourceManager.GetString("ForgetPasswordMessage", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Forget password. - /// - public static string ForgetPasswordTitle { - get { - return ResourceManager.GetString("ForgetPasswordTitle", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Forgot password?. - /// - public static string ForgotPasswordLink { - get { - return ResourceManager.GetString("ForgotPasswordLink", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Full Name. - /// - public static string FullName { - get { - return ResourceManager.GetString("FullName", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Gender. - /// - public static string Gender { - get { - return ResourceManager.GetString("Gender", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Custom. - /// - public static string GenderCustom { - get { - return ResourceManager.GetString("GenderCustom", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Female. - /// - public static string GenderFemale { - get { - return ResourceManager.GetString("GenderFemale", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Male. - /// - public static string GenderMale { - get { - return ResourceManager.GetString("GenderMale", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to GitHub Repo. - /// - public static string GitHubRepo { - get { - return ResourceManager.GetString("GitHubRepo", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Go to today. - /// - public static string GoToToday { - get { - return ResourceManager.GetString("GoToToday", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Home. - /// - public static string Home { - get { - return ResourceManager.GetString("Home", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Create your multi-mode (WASM, Server, pre-rendering) Blazor app easily in the shortest time ever!. - /// - public static string HomeMessage { - get { - return ResourceManager.GetString("HomeMessage", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Bit.Websites.Sales Home. - /// - public static string HomeTitle { - get { - return ResourceManager.GetString("HomeTitle", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Looks like the confirmation link either is invalid or has expired.. - /// - public static string InvalidConfirmationLinkMessage { - get { - return ResourceManager.GetString("InvalidConfirmationLinkMessage", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Email '{0}' is invalid.. - /// - public static string InvalidEmail { - get { - return ResourceManager.GetString("InvalidEmail", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Role name '{0}' is invalid.. - /// - public static string InvalidRoleName { - get { - return ResourceManager.GetString("InvalidRoleName", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Invalid token.. - /// - public static string InvalidToken { - get { - return ResourceManager.GetString("InvalidToken", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Username '{0}' is invalid, can only contain letters or digits.. - /// - public static string InvalidUserName { - get { - return ResourceManager.GetString("InvalidUserName", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Is accept privacy policy?. - /// - public static string IsAcceptPrivacy { - get { - return ResourceManager.GetString("IsAcceptPrivacy", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Known error. - /// - public static string KnownException { - get { - return ResourceManager.GetString("KnownException", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The field of type {0} must be a string, array or ICollection type.. - /// - public static string LengthAttribute_InvalidValueType { - get { - return ResourceManager.GetString("LengthAttribute_InvalidValueType", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Cannot retrieve property '{0}' because localization failed. Type '{1}' is not public or does not contain a public static string property with the name '{2}'.. - /// - public static string LocalizableString_LocalizationFailed { - get { - return ResourceManager.GetString("LocalizableString_LocalizationFailed", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to A user with this login already exists.. - /// - public static string LoginAlreadyAssociated { - get { - return ResourceManager.GetString("LoginAlreadyAssociated", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to MaxLengthAttribute must have a Length value that is greater than zero. Use MaxLength() without parameters to indicate that the string or array can have the maximum allowable length.. - /// - public static string MaxLengthAttribute_InvalidMaxLength { - get { - return ResourceManager.GetString("MaxLengthAttribute_InvalidMaxLength", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The field {0} must be a string or array type with a maximum length of '{1}'.. - /// - public static string MaxLengthAttribute_ValidationError { - get { - return ResourceManager.GetString("MaxLengthAttribute_ValidationError", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to MetadataClassType cannot be null.. - /// - public static string MetadataTypeAttribute_TypeCannotBeNull { - get { - return ResourceManager.GetString("MetadataTypeAttribute_TypeCannotBeNull", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to MinLengthAttribute must have a Length value that is zero or greater.. - /// - public static string MinLengthAttribute_InvalidMinLength { - get { - return ResourceManager.GetString("MinLengthAttribute_InvalidMinLength", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to {0} must be at least {1} characters.. - /// - public static string MinLengthAttribute_ValidationError { - get { - return ResourceManager.GetString("MinLengthAttribute_ValidationError", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to New Password. - /// - public static string NewPassword { - get { - return ResourceManager.GetString("NewPassword", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to No todos yet. - /// - public static string NoTodos { - get { - return ResourceManager.GetString("NoTodos", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Haven’t you received the confirmation email?. - /// - public static string NotReceivedConfirmationEmailMessage { - get { - return ResourceManager.GetString("NotReceivedConfirmationEmailMessage", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Haven’t you received the confirmation email?. - /// - public static string NotReceivedConfirmationEmailMessage1 { - get { - return ResourceManager.GetString("NotReceivedConfirmationEmailMessage1", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to OR. - /// - public static string Or { - get { - return ResourceManager.GetString("Or", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Password. - /// - public static string Password { - get { - return ResourceManager.GetString("Password", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Your password changed successfully.. - /// - public static string PasswordChangedSuccessfullyMessage { - get { - return ResourceManager.GetString("PasswordChangedSuccessfullyMessage", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Incorrect password.. - /// - public static string PasswordMismatch { - get { - return ResourceManager.GetString("PasswordMismatch", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Passwords must have at least one digit ('0'-'9').. - /// - public static string PasswordRequiresDigit { - get { - return ResourceManager.GetString("PasswordRequiresDigit", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Passwords must have at least one lowercase ('a'-'z').. - /// - public static string PasswordRequiresLower { - get { - return ResourceManager.GetString("PasswordRequiresLower", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Passwords must have at least one non alphanumeric character.. - /// - public static string PasswordRequiresNonAlphanumeric { - get { - return ResourceManager.GetString("PasswordRequiresNonAlphanumeric", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Passwords must use at least {0} different characters.. - /// - public static string PasswordRequiresUniqueChars { - get { - return ResourceManager.GetString("PasswordRequiresUniqueChars", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Passwords must have at least one uppercase ('A'-'Z').. - /// - public static string PasswordRequiresUpper { - get { - return ResourceManager.GetString("PasswordRequiresUpper", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The {0} field is not a valid phone number.. - /// - public static string PhoneAttribute_Invalid { - get { - return ResourceManager.GetString("PhoneAttribute_Invalid", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Phone number. - /// - public static string PhoneNumber { - get { - return ResourceManager.GetString("PhoneNumber", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Privacy. - /// - public static string Privacy { - get { - return ResourceManager.GetString("Privacy", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to I agree to the . - /// - public static string PrivacyPolicyAgreementMessage { - get { - return ResourceManager.GetString("PrivacyPolicyAgreementMessage", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Use this page to detail your site's privacy policy.. - /// - public static string PrivacyPolicyPageMessage { - get { - return ResourceManager.GetString("PrivacyPolicyPageMessage", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Use this section to detail your site's privacy policy.. - /// - public static string PrivacyPolicySectionMessage { - get { - return ResourceManager.GetString("PrivacyPolicySectionMessage", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Privacy Policy. - /// - public static string PrivacyPolicyTitle { - get { - return ResourceManager.GetString("PrivacyPolicyTitle", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Profile Image. - /// - public static string ProfileImage { - get { - return ResourceManager.GetString("ProfileImage", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Profile updated successfully.. - /// - public static string ProfileUpdatedSuccessfullyMessage { - get { - return ResourceManager.GetString("ProfileUpdatedSuccessfullyMessage", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The type {0} must implement {1}.. - /// - public static string RangeAttribute_ArbitraryTypeNotIComparable { - get { - return ResourceManager.GetString("RangeAttribute_ArbitraryTypeNotIComparable", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The maximum value '{0}' must be greater than or equal to the minimum value '{1}'.. - /// - public static string RangeAttribute_MinGreaterThanMax { - get { - return ResourceManager.GetString("RangeAttribute_MinGreaterThanMax", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The minimum and maximum values must be set.. - /// - public static string RangeAttribute_Must_Set_Min_And_Max { - get { - return ResourceManager.GetString("RangeAttribute_Must_Set_Min_And_Max", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The OperandType must be set when strings are used for minimum and maximum values.. - /// - public static string RangeAttribute_Must_Set_Operand_Type { - get { - return ResourceManager.GetString("RangeAttribute_Must_Set_Operand_Type", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The field {0} must be between {1} and {2}.. - /// - public static string RangeAttribute_ValidationError { - get { - return ResourceManager.GetString("RangeAttribute_ValidationError", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Recovery code redemption failed.. - /// - public static string RecoveryCodeRedemptionFailed { - get { - return ResourceManager.GetString("RecoveryCodeRedemptionFailed", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The field {0} must match the regular expression '{1}'.. - /// - public static string RegexAttribute_ValidationError { - get { - return ResourceManager.GetString("RegexAttribute_ValidationError", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The pattern must be set to a valid regular expression.. - /// - public static string RegularExpressionAttribute_Empty_Pattern { - get { - return ResourceManager.GetString("RegularExpressionAttribute_Empty_Pattern", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Remove. - /// - public static string Remove { - get { - return ResourceManager.GetString("Remove", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The {0} field is required.. - /// - public static string RequiredAttribute_ValidationError { - get { - return ResourceManager.GetString("RequiredAttribute_ValidationError", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The confirmation link has been re-sent to your email address.. - /// - public static string ResendConfirmationLinkMessage { - get { - return ResourceManager.GetString("ResendConfirmationLinkMessage", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Resend email. - /// - public static string ResendEmail { - get { - return ResourceManager.GetString("ResendEmail", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Reset password. - /// - public static string ResetPassword { - get { - return ResourceManager.GetString("ResetPassword", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The reset password link has been sent to your email address.. - /// - public static string ResetPasswordLinkSentMessage { - get { - return ResourceManager.GetString("ResetPasswordLinkSentMessage", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Reset password. - /// - public static string ResetPasswordTitle { - get { - return ResourceManager.GetString("ResetPasswordTitle", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Resource not found. - /// - public static string ResourceNotFoundException { - get { - return ResourceManager.GetString("ResourceNotFoundException", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Request data is not valid. - /// - public static string ResourceValidationException { - get { - return ResourceManager.GetString("ResourceValidationException", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to An error occurred while communicating with server. - /// - public static string RestException { - get { - return ResourceManager.GetString("RestException", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Role {0} does not exist.. - /// - public static string RoleNotFound { - get { - return ResourceManager.GetString("RoleNotFound", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Save. - /// - public static string Save { - get { - return ResourceManager.GetString("Save", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Select your birth date. - /// - public static string SelectBirthDate { - get { - return ResourceManager.GetString("SelectBirthDate", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Sign in. - /// - public static string SignIn { - get { - return ResourceManager.GetString("SignIn", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Sign in. - /// - public static string SignInTitle { - get { - return ResourceManager.GetString("SignInTitle", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Sign out. - /// - public static string SignOut { - get { - return ResourceManager.GetString("SignOut", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Are you sure you want to Sign out?. - /// - public static string SignOutPrompt { - get { - return ResourceManager.GetString("SignOutPrompt", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Sign up. - /// - public static string SignUp { - get { - return ResourceManager.GetString("SignUp", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Sign up. - /// - public static string SingUpTitle { - get { - return ResourceManager.GetString("SingUpTitle", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Sort by. - /// - public static string SortBy { - get { - return ResourceManager.GetString("SortBy", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The maximum length must be a nonnegative integer.. - /// - public static string StringLengthAttribute_InvalidMaxLength { - get { - return ResourceManager.GetString("StringLengthAttribute_InvalidMaxLength", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The field {0} must be a string with a maximum length of {1}.. - /// - public static string StringLengthAttribute_ValidationError { - get { - return ResourceManager.GetString("StringLengthAttribute_ValidationError", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The field {0} must be a string with a minimum length of {2} and a maximum length of {1}.. - /// - public static string StringLengthAttribute_ValidationErrorIncludingMinimum { - get { - return ResourceManager.GetString("StringLengthAttribute_ValidationErrorIncludingMinimum", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Submit. - /// - public static string Submit { - get { - return ResourceManager.GetString("Submit", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Title. - /// - public static string Title { - get { - return ResourceManager.GetString("Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Add a todo. - /// - public static string TodoAddPlaceholder { - get { - return ResourceManager.GetString("TodoAddPlaceholder", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Todo item could not be found. - /// - public static string ToDoItemCouldNotBeFound { - get { - return ResourceManager.GetString("ToDoItemCouldNotBeFound", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Search some todo.... - /// - public static string TodoSearchPlaceholder { - get { - return ResourceManager.GetString("TodoSearchPlaceholder", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Todo. - /// - public static string TodoTitle { - get { - return ResourceManager.GetString("TodoTitle", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Too many requests. - /// - public static string TooManyRequestsExceptions { - get { - return ResourceManager.GetString("TooManyRequestsExceptions", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The key parameter at position {0} with value '{1}' is not a string. Every key control parameter must be a string.. - /// - public static string UIHintImplementation_ControlParameterKeyIsNotAString { - get { - return ResourceManager.GetString("UIHintImplementation_ControlParameterKeyIsNotAString", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The key parameter at position {0} is null. Every key control parameter must be a string.. - /// - public static string UIHintImplementation_ControlParameterKeyIsNull { - get { - return ResourceManager.GetString("UIHintImplementation_ControlParameterKeyIsNull", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The key parameter at position {0} with value '{1}' occurs more than once.. - /// - public static string UIHintImplementation_ControlParameterKeyOccursMoreThanOnce { - get { - return ResourceManager.GetString("UIHintImplementation_ControlParameterKeyOccursMoreThanOnce", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The number of control parameters must be even.. - /// - public static string UIHintImplementation_NeedEvenNumberOfControlParameters { - get { - return ResourceManager.GetString("UIHintImplementation_NeedEvenNumberOfControlParameters", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Your request lacks valid authentication credentials. - /// - public static string UnauthorizedException { - get { - return ResourceManager.GetString("UnauthorizedException", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Unknown error has occurred. - /// - public static string UnknownException { - get { - return ResourceManager.GetString("UnknownException", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The record was modified by another user after you got the original data. the operation was canceled.. - /// - public static string UpdateConcurrencyException { - get { - return ResourceManager.GetString("UpdateConcurrencyException", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Upload a new profile image. - /// - public static string UploadNewProfileImage { - get { - return ResourceManager.GetString("UploadNewProfileImage", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The {0} field is not a valid fully-qualified http, https, or ftp URL.. - /// - public static string UrlAttribute_Invalid { - get { - return ResourceManager.GetString("UrlAttribute_Invalid", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to User already has a password set.. - /// - public static string UserAlreadyHasPassword { - get { - return ResourceManager.GetString("UserAlreadyHasPassword", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to User already in role '{0}'.. - /// - public static string UserAlreadyInRole { - get { - return ResourceManager.GetString("UserAlreadyInRole", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to User image could not be found. - /// - public static string UserImageCouldNotBeFound { - get { - return ResourceManager.GetString("UserImageCouldNotBeFound", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to User is locked out. Try again in {0}. - /// - public static string UserLockedOut { - get { - return ResourceManager.GetString("UserLockedOut", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Username. - /// - public static string UserName { - get { - return ResourceManager.GetString("UserName", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to User {0} does not exist.. - /// - public static string UserNameNotFound { - get { - return ResourceManager.GetString("UserNameNotFound", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to User is not in role '{0}'.. - /// - public static string UserNotInRole { - get { - return ResourceManager.GetString("UserNotInRole", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Either ErrorMessageString or ErrorMessageResourceName must be set, but not both.. - /// - public static string ValidationAttribute_Cannot_Set_ErrorMessage_And_Resource { - get { - return ResourceManager.GetString("ValidationAttribute_Cannot_Set_ErrorMessage_And_Resource", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to IsValid(object value) has not been implemented by this class. The preferred entry point is GetValidationResult() and classes should override IsValid(object value, ValidationContext context).. - /// - public static string ValidationAttribute_IsValid_NotImplemented { - get { - return ResourceManager.GetString("ValidationAttribute_IsValid_NotImplemented", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Both ErrorMessageResourceType and ErrorMessageResourceName need to be set on this attribute.. - /// - public static string ValidationAttribute_NeedBothResourceTypeAndResourceName { - get { - return ResourceManager.GetString("ValidationAttribute_NeedBothResourceTypeAndResourceName", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The property '{0}' on resource type '{1}' is not a string type.. - /// - public static string ValidationAttribute_ResourcePropertyNotStringType { - get { - return ResourceManager.GetString("ValidationAttribute_ResourcePropertyNotStringType", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The resource type '{0}' does not have an accessible static property named '{1}'.. - /// - public static string ValidationAttribute_ResourceTypeDoesNotHaveProperty { - get { - return ResourceManager.GetString("ValidationAttribute_ResourceTypeDoesNotHaveProperty", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The field {0} is invalid.. - /// - public static string ValidationAttribute_ValidationError { - get { - return ResourceManager.GetString("ValidationAttribute_ValidationError", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The instance provided must match the ObjectInstance on the ValidationContext supplied.. - /// - public static string Validator_InstanceMustMatchValidationContextInstance { - get { - return ResourceManager.GetString("Validator_InstanceMustMatchValidationContextInstance", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to The value for property '{0}' must be of type '{1}'.. - /// - public static string Validator_Property_Value_Wrong_Type { - get { - return ResourceManager.GetString("Validator_Property_Value_Wrong_Type", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to You have already requested the confirmation email. Try again in {0}. - /// - public static string WaitForConfirmationEmailResendDelay { - get { - return ResourceManager.GetString("WaitForConfirmationEmailResendDelay", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to You have already requested the reset password email. Try again in {0}. - /// - public static string WaitForResetPasswordEmailResendDelay { - get { - return ResourceManager.GetString("WaitForResetPasswordEmailResendDelay", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to You must agree to our privacy policy.. - /// - public static string YouHaveToAcceptPrivacyPolicy { - get { - return ResourceManager.GetString("YouHaveToAcceptPrivacyPolicy", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to You must be signed in to continue.. - /// - public static string YouNeedToSignIn { - get { - return ResourceManager.GetString("YouNeedToSignIn", resourceCulture); - } - } - } -} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Resources/AppStrings.resx b/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Resources/AppStrings.resx deleted file mode 100644 index 18bbb064c5..0000000000 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Resources/AppStrings.resx +++ /dev/null @@ -1,652 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Invalid request - - - Request could not be processed because of conflict in the request - - - An error occurred while removing file - - - An error occurred while uploading file - - - Access to the requested resource is forbidden - - - Request data is not valid - - - An error occurred while communicating with server - - - Todo item could not be found - - - Your request lacks valid authentication credentials - - - Unknown error has occurred - - - User image could not be found - - - Optimistic concurrency failure, object has been modified. - Error when optimistic concurrency fails - - - Email '{0}' is already taken. - Error for duplicate emails - - - Role name '{0}' is already taken. - Error for duplicate roles - - - Username '{0}' is already taken. - Error for duplicate user names - - - Email '{0}' is invalid. - Invalid email - - - Role name '{0}' is invalid. - Error for invalid role names - - - Invalid token. - Error when a token is not recognized - - - Username '{0}' is invalid, can only contain letters or digits. - User names can only contain letters or digits - - - A user with this login already exists. - Error when a login already linked - - - Incorrect password. - Error when a password doesn't match - - - Passwords must have at least one digit ('0'-'9'). - Error when passwords do not have a digit - - - Passwords must have at least one lowercase ('a'-'z'). - Error when passwords do not have a lowercase letter - - - Passwords must have at least one non alphanumeric character. - Error when password does not have enough non alphanumeric characters - - - Passwords must have at least one uppercase ('A'-'Z'). - Error when passwords do not have an uppercase letter - - - {0} must be at least {1} characters. - Error message for passwords that are too short - - - Role {0} does not exist. - Error when a role does not exist - - - Recovery code redemption failed. - Error when a recovery code is not redeemed. - - - User already has a password set. - Error when AddPasswordAsync called when a user already has a password - - - User already in role '{0}'. - Error when a user is already in a role - - - User is locked out. Try again in {0} - Error when a user is locked out - - - User {0} does not exist. - Error when a user does not exist - - - User is not in role '{0}'. - Error when a user is not in the role - - - Passwords must use at least {0} different characters. - Error message for passwords that are based on similar characters - - - Email '{0}' is not confirmed. - Error when a email is not confirmed by the confirmation link - - - You have already requested the confirmation email. Try again in {0} - - - You have already requested the reset password email. Try again in {0} - - - Your email is already confirmed. - - - The record was modified by another user after you got the original data. the operation was canceled. - - - Known error - - - Resource not found - - - Too many requests - - - Error - - - Active - - - Add - - - All - - - Alphabetical - - - Already have an account? - - - Cancel - - - Check your Spam/Junk, if you could not find it in the Inbox. - - - Completed - - - We have sent a confirmation link to your email address. -Please confirm your email by clicking on the link. - - - Confirm Your Email Address - - - Confirm New Password - - - Date - - - Don’t have an account? - - - Edit - - - Edit profile - - - Email - - - Email Confirmation Failed! - - - Email Confirmation - - - Email Confirmed Successfully! - - - Please enter the email address you have been signed up with so we can send a reset password link to your email address. - - - Forget password - - - Forgot password? - - - Full Name - - - Custom - - - Female - - - Male - - - GitHub Repo - - - Looks like the confirmation link either is invalid or has expired. - - - New Password - - - No todos yet - - - Haven’t you received the confirmation email? - - - Haven’t you received the confirmation email? - - - OR - - - Password - - - Your password changed successfully. - - - I agree to the - - - Use this page to detail your site's privacy policy. - - - Use this section to detail your site's privacy policy. - - - Privacy Policy - - - Profile updated successfully. - - - Remove - - - The confirmation link has been re-sent to your email address. - - - Resend email - - - Reset password - - - The reset password link has been sent to your email address. - - - Reset password - - - Save - - - Select your birth date - - - Sign in - - - Sign in - - - Sign out - - - Sign up - - - Sign up - - - Sort by - - - Submit - - - Add a todo - - - Search some todo... - - - Create your multi-mode (WASM, Server, pre-rendering) Blazor app easily in the shortest time ever! - - - Bit.Websites.Sales Home - - - Todo - - - Upload a new profile image - - - The argument '{0}' cannot be null, empty or contain only whitespace. - - - The associated metadata type for type '{0}' contains the following unknown properties or fields: {1}. Please make sure that the names of these members match the names of the properties on the main type. - - - The type '{0}' does not contain a public property named '{1}'. - - - The property {0}.{1} could not be found. - - - '{0}' and '{1}' do not match. - - - Could not find a property named {0}. - - - The {0} field is not a valid credit card number. - - - The CustomValidationAttribute method '{0}' in type '{1}' must return System.ComponentModel.DataAnnotations.ValidationResult. Use System.ComponentModel.DataAnnotations.ValidationResult.Success to represent success. - - - The CustomValidationAttribute method '{0}' does not exist in type '{1}' or is not public and static. - - - The CustomValidationAttribute.Method was not specified. - - - The CustomValidationAttribute method '{0}' in type '{1}' must match the expected signature: public static ValidationResult {0}(object value, ValidationContext context). The value can be strongly typed. The ValidationContext parameter is optional. - - - Could not convert the value of type '{0}' to '{1}' as expected by method {2}.{3}. - - - The custom validation type '{0}' must be public. - - - {0} is not valid. - - - The CustomValidationAttribute.ValidatorType was not specified. - - - The custom DataType string cannot be null or empty. - - - The {0} property has not been set. Use the {1} method to get the value. - - - The {0} field is not a valid e-mail address. - - - The type provided for EnumDataTypeAttribute cannot be null. - - - The type '{0}' needs to represent an enumeration type. - - - The {0} field only accepts files with the following extensions: {1} - - - The field of type {0} must be a string, array or ICollection type. - - - Cannot retrieve property '{0}' because localization failed. Type '{1}' is not public or does not contain a public static string property with the name '{2}'. - - - MaxLengthAttribute must have a Length value that is greater than zero. Use MaxLength() without parameters to indicate that the string or array can have the maximum allowable length. - - - The field {0} must be a string or array type with a maximum length of '{1}'. - - - MetadataClassType cannot be null. - - - MinLengthAttribute must have a Length value that is zero or greater. - - - The {0} field is not a valid phone number. - - - The type {0} must implement {1}. - - - The maximum value '{0}' must be greater than or equal to the minimum value '{1}'. - - - The minimum and maximum values must be set. - - - The OperandType must be set when strings are used for minimum and maximum values. - - - The field {0} must be between {1} and {2}. - - - The field {0} must match the regular expression '{1}'. - - - The pattern must be set to a valid regular expression. - - - The {0} field is required. - - - The maximum length must be a nonnegative integer. - - - The field {0} must be a string with a maximum length of {1}. - - - The field {0} must be a string with a minimum length of {2} and a maximum length of {1}. - - - The key parameter at position {0} with value '{1}' is not a string. Every key control parameter must be a string. - - - The key parameter at position {0} is null. Every key control parameter must be a string. - - - The key parameter at position {0} with value '{1}' occurs more than once. - - - The number of control parameters must be even. - - - The {0} field is not a valid fully-qualified http, https, or ftp URL. - - - Either ErrorMessageString or ErrorMessageResourceName must be set, but not both. - - - IsValid(object value) has not been implemented by this class. The preferred entry point is GetValidationResult() and classes should override IsValid(object value, ValidationContext context). - - - Both ErrorMessageResourceType and ErrorMessageResourceName need to be set on this attribute. - - - The property '{0}' on resource type '{1}' is not a string type. - - - The resource type '{0}' does not have an accessible static property named '{1}'. - - - The field {0} is invalid. - - - The instance provided must match the ObjectInstance on the ValidationContext supplied. - - - The value for property '{0}' must be of type '{1}'. - - - Is accept privacy policy? - - - Phone number - - - Username - - - You must agree to our privacy policy. - - - Go to today - - - Gender - - - Privacy - - - Are you sure you want to Sign out? - - - Birthdate - - - Home - - - Profile Image - - - Title - - - You must be signed in to continue. - - \ No newline at end of file diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Resources/StringLocalizerProvider.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Resources/StringLocalizerProvider.cs deleted file mode 100644 index 103e0e996d..0000000000 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Shared/Resources/StringLocalizerProvider.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Reflection; - -namespace Bit.Websites.Sales.Shared.Resources; - -public static class StringLocalizerProvider -{ - public static IStringLocalizer ProvideLocalizer(Type dtoType, IStringLocalizerFactory factory) - { - return factory.Create(dtoType.GetCustomAttribute()?.ResourceType ?? typeof(AppStrings)); - } -} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/App.razor.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Web/App.razor.cs deleted file mode 100644 index 40c0edc347..0000000000 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Web/App.razor.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace Bit.Websites.Sales.Web; - -public partial class App -{ -} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Components/AppDataAnnotationsValidator.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Web/Components/AppDataAnnotationsValidator.cs deleted file mode 100644 index 727bd1ebb6..0000000000 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Components/AppDataAnnotationsValidator.cs +++ /dev/null @@ -1,189 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; -using Microsoft.AspNetCore.Components.Forms; -using Bit.Websites.Sales.Shared.Attributes; - -namespace Bit.Websites.Sales.Web.Components; - -public partial class AppDataAnnotationsValidator : AppComponentBase, IDisposable -{ - private static readonly PropertyInfo _OtherPropertyNamePropertyInfo = - typeof(CompareAttribute).GetProperty(nameof(CompareAttribute.OtherPropertyDisplayName))!; - - private bool _disposed; - private ValidationMessageStore _validationMessageStore = default!; - - [AutoInject] private IServiceProvider _serviceProvider = default!; - [AutoInject] private IStringLocalizerFactory _stringLocalizerFactory = default!; - - [CascadingParameter] private EditContext _editContext { get; set; } = default!; - - protected override Task OnInitAsync() - { - if (_editContext is null) - throw new InvalidOperationException("EditContext is required"); - - _editContext.OnFieldChanged += OnFieldChanged; - _editContext.OnValidationRequested += OnValidationRequested; - - _validationMessageStore = new ValidationMessageStore(_editContext); - - return base.OnInitAsync(); - } - - private void OnFieldChanged(object? sender, FieldChangedEventArgs eventArgs) - { - var fieldIdentifier = eventArgs.FieldIdentifier; - var propertyInfo = fieldIdentifier.Model.GetType().GetProperty(fieldIdentifier.FieldName); - if (propertyInfo is null) return; - - var propertyValue = propertyInfo.GetValue(fieldIdentifier.Model); - var validationContext = new ValidationContext(fieldIdentifier.Model, _serviceProvider, items: null) - { - MemberName = propertyInfo.Name - }; - var results = new List(); - - var parent = propertyInfo.DeclaringType!; - var dtoResourceTypeAttr = parent.GetCustomAttribute(); - if (dtoResourceTypeAttr is null) - { - Validator.TryValidateProperty(propertyValue, validationContext, results); - } - else - { - var resourceType = dtoResourceTypeAttr.ResourceType; - var stringLocalizer = _stringLocalizerFactory.Create(resourceType); - var validationAttributes = propertyInfo.GetCustomAttributes(); - - foreach (var attribute in validationAttributes) - { - if (string.IsNullOrWhiteSpace(attribute.ErrorMessageResourceName) is false && attribute.ErrorMessageResourceType is null) - { - attribute.ErrorMessageResourceType = resourceType; - var displayAttribute = propertyInfo.GetCustomAttribute(); - validationContext.DisplayName = stringLocalizer.GetString(displayAttribute?.Name ?? propertyInfo.Name); - - if (attribute is CompareAttribute compareAttribute) - { - var otherPropertyInfoDisplayAttribute = (parent.GetProperty(compareAttribute.OtherProperty) ?? throw new InvalidOperationException($"Invalid OtherProperty {compareAttribute.OtherProperty}")).GetCustomAttribute(); - _OtherPropertyNamePropertyInfo.SetValue(attribute, stringLocalizer.GetString(otherPropertyInfoDisplayAttribute?.Name ?? compareAttribute.OtherProperty).ToString()); - } - } - - var result = attribute.GetValidationResult(propertyValue, validationContext); - - if (result is not null) - { - results.Add(result); - } - } - - } - - _validationMessageStore.Clear(fieldIdentifier); - - foreach (var result in CollectionsMarshal.AsSpan(results)) - { - _validationMessageStore.Add(fieldIdentifier, result.ErrorMessage!); - } - - _editContext.NotifyValidationStateChanged(); - } - - private void OnValidationRequested(object? sender, ValidationRequestedEventArgs e) - { - var validationContext = new ValidationContext(_editContext.Model, _serviceProvider, items: null); - var results = new List(); - - var objectType = validationContext.ObjectType; - var objectInstance = validationContext.ObjectInstance; - var dtoResourceTypeAttr = objectType.GetCustomAttribute(); - - _validationMessageStore.Clear(); - - if (dtoResourceTypeAttr is null) - { - Validator.TryValidateObject(_editContext.Model, validationContext, results, true); - } - else - { - var resourceType = dtoResourceTypeAttr.ResourceType; - - var stringLocalizer = _stringLocalizerFactory.Create(resourceType); - - var properties = objectType.GetProperties(BindingFlags.Instance | BindingFlags.Public); - - foreach (var propertyInfo in properties) - { - var context = new ValidationContext(objectInstance, validationContext, validationContext.Items) { MemberName = propertyInfo.Name }; - var propertyValue = propertyInfo.GetValue(objectInstance); - var validationAttributes = propertyInfo.GetCustomAttributes(); - foreach (var attribute in validationAttributes) - { - if (string.IsNullOrWhiteSpace(attribute.ErrorMessageResourceName) is false && attribute.ErrorMessageResourceType is null) - { - attribute.ErrorMessageResourceType = resourceType; - var displayAttribute = propertyInfo.GetCustomAttribute(); - validationContext.DisplayName = stringLocalizer.GetString(displayAttribute?.Name ?? propertyInfo.Name); - if (attribute is CompareAttribute compareAttribute) - { - var otherPropertyInfoDisplayAttribute = (properties.FirstOrDefault(p => p.Name == compareAttribute.OtherProperty) - ?? throw new InvalidOperationException($"Invalid OtherProperty {compareAttribute.OtherProperty}")).GetCustomAttribute(); - - _OtherPropertyNamePropertyInfo.SetValue(attribute, stringLocalizer.GetString(otherPropertyInfoDisplayAttribute?.Name - ?? compareAttribute.OtherProperty).ToString()); - } - } - - var result = attribute.GetValidationResult(propertyValue, context); - - if (result is not null) - { - results.Add(result); - } - } - } - } - - _validationMessageStore.Clear(); - - foreach (var validationResult in results) - { - if (validationResult == null) continue; - - var hasMemberNames = false; - - foreach (var memberName in validationResult.MemberNames) - { - hasMemberNames = true; - _validationMessageStore.Add(_editContext.Field(memberName), validationResult.ErrorMessage!); - } - - if (hasMemberNames) continue; - - _validationMessageStore.Add(new FieldIdentifier(_editContext.Model, fieldName: string.Empty), validationResult.ErrorMessage!); - } - - _editContext.NotifyValidationStateChanged(); - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - protected virtual void Dispose(bool disposing) - { - if (_disposed || disposing is false) return; - - if (_editContext is not null) - { - _editContext.OnFieldChanged -= OnFieldChanged; - _editContext.OnValidationRequested -= OnValidationRequested; - } - - _disposed = true; - } -} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Components/PageNotFound.razor b/src/Websites/Sales/src/Bit.Websites.Sales.Web/Components/PageNotFound.razor deleted file mode 100644 index 1b2c3d786b..0000000000 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Components/PageNotFound.razor +++ /dev/null @@ -1,8 +0,0 @@ -@inherits AppComponentBase; - - - -
-

404

-
There is nothing here.
-
\ No newline at end of file diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Extensions/IServiceCollectionExtensions.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Web/Extensions/IServiceCollectionExtensions.cs deleted file mode 100644 index efa43dd30b..0000000000 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Extensions/IServiceCollectionExtensions.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace Microsoft.Extensions.DependencyInjection; - -public static class IServiceCollectionExtensions -{ - public static IServiceCollection AddClientSharedServices(this IServiceCollection services) - { - services.AddScoped(); - services.AddScoped(); - services.AddScoped(); - - services.AddTransient(); - - return services; - } -} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Extensions/ResourceManagerExtensions.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Web/Extensions/ResourceManagerExtensions.cs deleted file mode 100644 index 18faa7ccb7..0000000000 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Extensions/ResourceManagerExtensions.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace System.Resources; - -public static class ResourceManagerExtensions -{ - public static string Translate(this ResourceManager resourceManager, string name, params string?[] args) - { - return string.Format(resourceManager.GetString(name) ?? name, args); - } -} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Pages/CasesPage.razor.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Web/Pages/CasesPage.razor.cs deleted file mode 100644 index 6e1468581f..0000000000 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Pages/CasesPage.razor.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace Bit.Websites.Sales.Web.Pages; - -public partial class ShowCasePage -{ -} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Pages/_Host.cshtml b/src/Websites/Sales/src/Bit.Websites.Sales.Web/Pages/_Host.cshtml deleted file mode 100644 index b17605704e..0000000000 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Pages/_Host.cshtml +++ /dev/null @@ -1,21 +0,0 @@ -@page "/" -@using Bit.Websites.Sales.Web; -@using Bit.Websites.Sales.Shared.Infra; -@namespace Bit.Websites.Sales.Web.Pages -@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers -@{ - Layout = "_Layout"; - var isBlazorServer = BlazorModeDetector.Current.IsBlazorServer(); - var isStatic = WebAppDeploymentTypeDetector.Current.IsStatic(); - RenderMode renderMode = isBlazorServer ? RenderMode.ServerPrerendered : RenderMode.WebAssemblyPrerendered; - - if (renderMode is RenderMode.ServerPrerendered or RenderMode.WebAssemblyPrerendered) - { - if (Request.ShouldRenderStaticMode()) - { - renderMode = RenderMode.Static; - } - } -} - - diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Pages/_Layout.cshtml b/src/Websites/Sales/src/Bit.Websites.Sales.Web/Pages/_Layout.cshtml deleted file mode 100644 index eb5af74c91..0000000000 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Pages/_Layout.cshtml +++ /dev/null @@ -1,105 +0,0 @@ -@using Bit.Websites.Sales.Shared.Infra -@using Microsoft.AspNetCore.Components.Web -@using RenderMode = Microsoft.AspNetCore.Mvc.Rendering.RenderMode - -@namespace Bit.Websites.Sales.Web.Pages -@inject IHttpContextAccessor ContextAccessor -@inject IConfiguration Configuration -@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers -@{ - var gtmId = @Configuration.GetSection("GoogleTagManager")["Id"]; - var isBlazorServer = BlazorModeDetector.Current.IsBlazorServer(); - var isStatic = WebAppDeploymentTypeDetector.Current.IsStatic(); - var isSsr = WebAppDeploymentTypeDetector.Current.IsSsr(); - - RenderMode renderMode = isBlazorServer ? RenderMode.ServerPrerendered : RenderMode.WebAssemblyPrerendered; - - if (renderMode is RenderMode.ServerPrerendered or RenderMode.WebAssemblyPrerendered) - { - var shouldRenderStaticMode = ContextAccessor?.HttpContext?.Request.ShouldRenderStaticMode(); - - if (shouldRenderStaticMode is not null && shouldRenderStaticMode.Value) - { - renderMode = RenderMode.Static; - isStatic = true; - } - } -} - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- @RenderBody() -
- - @if (isStatic is false) - { - @if (isBlazorServer) - { - - } - else - { - - - - - @if (isSsr) - { - - } - else - { - - - } - } - - } - - - @if (isSsr) - { - - } - - \ No newline at end of file diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Program.BlazorServer.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Web/Program.BlazorServer.cs deleted file mode 100644 index 76df29a68d..0000000000 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Program.BlazorServer.cs +++ /dev/null @@ -1,24 +0,0 @@ -#if BlazorServer -#endif - -namespace Bit.Websites.Sales.Web; - -public partial class Program -{ -#if BlazorServer - public static WebApplication CreateHostBuilder(string[] args) - { - var builder = WebApplication.CreateBuilder(args); - - builder.Configuration.AddClientConfigurations(); - - Startup.Services.Add(builder.Services, builder.Configuration); - - var app = builder.Build(); - - Startup.Middlewares.Use(app, builder.Environment); - - return app; - } -#endif -} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Program.BlazorWebAssembly.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Web/Program.BlazorWebAssembly.cs deleted file mode 100644 index c26ccd7836..0000000000 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Program.BlazorWebAssembly.cs +++ /dev/null @@ -1,38 +0,0 @@ -#if BlazorWebAssembly -using Microsoft.AspNetCore.Components.WebAssembly.Hosting; -#endif - -namespace Bit.Websites.Sales.Web; - -public partial class Program -{ -#if BlazorWebAssembly - public static WebAssemblyHost CreateHostBuilder(string[] args) - { - var builder = WebAssemblyHostBuilder.CreateDefault(); - builder.Configuration.AddClientConfigurations(); - - Uri.TryCreate(builder.Configuration.GetApiServerAddress(), UriKind.RelativeOrAbsolute, out var apiServerAddress); - - if (apiServerAddress.IsAbsoluteUri is false) - { - apiServerAddress = new Uri($"{builder.HostEnvironment.BaseAddress}{apiServerAddress}"); - } - - builder.Services.AddSingleton(sp => new HttpClient(sp.GetRequiredService()) { BaseAddress = apiServerAddress }); - builder.Services.AddScoped(); - - builder.Services.AddSharedServices(); - builder.Services.AddClientSharedServices(); - - var host = builder.Build(); - -#if MultilingualEnabled - var preferredCultureCookie = ((IJSInProcessRuntime)host.Services.GetRequiredService()).Invoke("window.App.getCookie", ".AspNetCore.Culture"); - CultureInfoManager.SetCurrentCulture(preferredCultureCookie); -#endif - - return host; - } -#endif -} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Program.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Web/Program.cs deleted file mode 100644 index 3e1bd34a69..0000000000 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Program.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Bit.Websites.Sales.Web; - -public partial class Program -{ - public static async Task Main(string[] args) - { -#if !BlazorWebAssembly && !BlazorServer - throw new InvalidOperationException("Please switch to either blazor webassembly or server as described in readme.md"); -#else - await CreateHostBuilder(args) - .RunAsync(); -#endif - } -} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Properties/launchSettings.json b/src/Websites/Sales/src/Bit.Websites.Sales.Web/Properties/launchSettings.json deleted file mode 100644 index e6f85ec389..0000000000 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Properties/launchSettings.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "profiles": { - "Bit.Websites.Sales.Web": { - "commandName": "Project", - "dotnetRunMessages": true, - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - }, - "applicationUrl": "https://localhost:4021;http://localhost:4020" - } - } -} \ No newline at end of file diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Services/AppHttpClientHandler.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Web/Services/AppHttpClientHandler.cs deleted file mode 100644 index be6af38b0b..0000000000 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Services/AppHttpClientHandler.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System.Net; - -namespace Bit.Websites.Sales.Web.Services; - -public partial class AppHttpClientHandler : HttpClientHandler -{ - protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) - { -#if MultilingualEnabled && BlazorServer - string cultureCookie = $"c={CultureInfo.CurrentCulture.Name}|uic={CultureInfo.CurrentCulture.Name}"; - request.Headers.Add("Cookie", $".AspNetCore.Culture={cultureCookie}"); -#endif - - var response = await base.SendAsync(request, cancellationToken); - - if (response.StatusCode is HttpStatusCode.Unauthorized) - { - throw new UnauthorizedException(); - } - - if (response.IsSuccessStatusCode is false && response.Content.Headers.ContentType?.MediaType?.Contains("application/json", StringComparison.InvariantCultureIgnoreCase) is true) - { - if (response.Headers.TryGetValues("Request-ID", out IEnumerable? values) && values is not null && values.Any()) - { - RestErrorInfo restError = await response.Content.ReadFromJsonAsync(AppJsonContext.Default.RestErrorInfo); - - Type exceptionType = typeof(RestErrorInfo).Assembly.GetType(restError.ExceptionType) ?? typeof(UnknownException); - - var args = new List { typeof(KnownException).IsAssignableFrom(exceptionType) ? new LocalizedString(restError.Key!, restError.Message!) : restError.Message }; - - if (exceptionType == typeof(ResourceValidationException)) - { - args.Add(restError.Payload); - } - - Exception exp = (Exception)Activator.CreateInstance(exceptionType, args.ToArray()); - - throw exp; - } - } - - response.EnsureSuccessStatusCode(); - - return response; - } -} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Services/Contracts/IPubSubService.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Web/Services/Contracts/IPubSubService.cs deleted file mode 100644 index 035da8a876..0000000000 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Services/Contracts/IPubSubService.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Bit.Websites.Sales.Web.Services.Contracts; - -public interface IPubSubService -{ - void Pub(string message, object? payload); - Action Sub(string message, Action handler); -} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Services/Contracts/IStateService.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Web/Services/Contracts/IStateService.cs deleted file mode 100644 index 936b47ba72..0000000000 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Services/Contracts/IStateService.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Bit.Websites.Sales.Web.Services.Contracts; - -public interface IStateService -{ - /// - /// Instead of using ApplicationState.TryTakeFromJson, ApplicationState.RegisterOnPersisting, and ApplicationState.PersistAsJson - /// (explained here: https://docs.microsoft.com/en-us/aspnet/core/blazor/components/prerendering-and-integration#persist-prerendered-state), - /// one can easily use the following method (StateService.GetValue) in the OnInit lifecycle method of the Blazor components - /// or pages to retrieve everything that requires an async-await (like current user's info). - /// - Task GetValue(string key, Func> factory); -} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Services/ExceptionHandler.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Web/Services/ExceptionHandler.cs deleted file mode 100644 index 32bb79d8c4..0000000000 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Services/ExceptionHandler.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System.Diagnostics; - -namespace Bit.Websites.Sales.Web.Services; - -public partial class ExceptionHandler : IExceptionHandler -{ - [AutoInject] IStringLocalizer _localizer = default!; - - public void Handle(Exception exception, IDictionary? parameters = null) - { -#if DEBUG - string exceptionMessage = (exception as KnownException)?.Message ?? exception.ToString(); - _ = MessageBox.Show(exceptionMessage, _localizer[nameof(AppStrings.Error)]); - Console.WriteLine(exceptionMessage); - Debugger.Break(); -#else - if (exception is KnownException knownException) - { - _ = MessageBox.Show(knownException.Message, _localizer[nameof(AppStrings.Error)]); - } - else - { - _ = MessageBox.Show(_localizer[nameof(AppStrings.UnknownException)], _localizer[nameof(AppStrings.Error)]); - } -#endif - } -} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Services/PubSubMessages.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Web/Services/PubSubMessages.cs deleted file mode 100644 index c90a1b747d..0000000000 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Services/PubSubMessages.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Bit.Websites.Sales.Web.Services; - -public static class PubSubMessages -{ - -} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Shared/BupProgressBar.razor b/src/Websites/Sales/src/Bit.Websites.Sales.Web/Shared/BupProgressBar.razor deleted file mode 100644 index 69cbad5b77..0000000000 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Shared/BupProgressBar.razor +++ /dev/null @@ -1,48 +0,0 @@ -@using Bit.Bup -@using Bit.BlazorUI - - - -@code { - private bool _showLoading = true; - - protected override void OnAfterRender(bool firstRender) - { - base.OnAfterRender(firstRender); - if (firstRender is false) return; - - _showLoading = false; - StateHasChanged(); - } -} - -@if (_showLoading) -{ -
- -
- - -
-} \ No newline at end of file diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Shared/MessageBox.razor.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Web/Shared/MessageBox.razor.cs deleted file mode 100644 index 3b8b9cef95..0000000000 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Shared/MessageBox.razor.cs +++ /dev/null @@ -1,56 +0,0 @@ -namespace Bit.Websites.Sales.Web.Shared; - -public partial class MessageBox : IDisposable -{ - private static event Func OnShow = default!; - - private bool _isOpen; - private string _title = string.Empty; - private string _body = string.Empty; - - private static TaskCompletionSource? _tsc; - - public static async Task Show(string message, string title = "") - { - _tsc = new TaskCompletionSource(); - - await OnShow.Invoke(message, title); - - await _tsc.Task; - } - - protected override void OnInitialized() - { - OnShow += ShowMessageBox; - - base.OnInitialized(); - } - - private async Task ShowMessageBox(string message, string title) - { - await InvokeAsync(() => - { - _isOpen = true; - - _title = title; - _body = message; - - StateHasChanged(); - }); - } - - private void OnCloseClick() - { - _isOpen = false; - _tsc?.SetResult(null); - } - - - private void OnOkClick() - { - _isOpen = false; - _tsc?.SetResult(null); - } - - public void Dispose() => OnShow -= ShowMessageBox; -} diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Startup/Middlewares.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Web/Startup/Middlewares.cs deleted file mode 100644 index 233faf361e..0000000000 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Startup/Middlewares.cs +++ /dev/null @@ -1,43 +0,0 @@ -#if BlazorServer -namespace Bit.Websites.Sales.Web.Startup; - -public class Middlewares -{ - public static void Use(IApplicationBuilder app, IHostEnvironment env) - { - if (env.IsDevelopment()) - { - app.UseDeveloperExceptionPage(); - } - else - { - app.UseExceptionHandler("/Error"); - } - - if (env.IsDevelopment() is false) - { - app.UseHttpsRedirection(); - app.UseResponseCompression(); - } - app.UseStaticFiles(); - - app.UseRouting(); - -#if MultilingualEnabled - var supportedCultures = CultureInfoManager.SupportedCultures.Select(sc => CultureInfoManager.CreateCultureInfo(sc.code)).ToArray(); - app.UseRequestLocalization(new RequestLocalizationOptions - { - SupportedCultures = supportedCultures, - SupportedUICultures = supportedCultures, - ApplyCurrentCultureToResponseHeaders = true - }.SetDefaultCulture(CultureInfoManager.DefaultCulture.code)); -#endif - - app.UseEndpoints(endpoints => - { - endpoints.MapBlazorHub(); - endpoints.MapFallbackToPage("/_Host"); - }); - } -} -#endif diff --git a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Startup/Services.cs b/src/Websites/Sales/src/Bit.Websites.Sales.Web/Startup/Services.cs deleted file mode 100644 index 45cc98dde0..0000000000 --- a/src/Websites/Sales/src/Bit.Websites.Sales.Web/Startup/Services.cs +++ /dev/null @@ -1,39 +0,0 @@ -#if BlazorServer -using System.IO.Compression; -using Microsoft.AspNetCore.ResponseCompression; - -namespace Bit.Websites.Sales.Web.Startup; - -public static class Services -{ - public static void Add(IServiceCollection services, IConfiguration configuration) - { - Uri.TryCreate(configuration.GetApiServerAddress(), UriKind.Absolute, out var apiServerAddress); - services.AddScoped(sp => - { - HttpClient httpClient = new(sp.GetRequiredService()) - { - BaseAddress = apiServerAddress - }; - - return httpClient; - }); - - services.AddHttpContextAccessor(); - services.AddRazorPages(); - services.AddServerSideBlazor(); - services.AddResponseCompression(opts => - { - opts.EnableForHttps = true; - opts.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(new[] { "application/octet-stream" }).ToArray(); - opts.Providers.Add(); - opts.Providers.Add(); - }) - .Configure(opt => opt.Level = CompressionLevel.Fastest) - .Configure(opt => opt.Level = CompressionLevel.Fastest); - - services.AddSharedServices(); - services.AddClientSharedServices(); - } -} -#endif diff --git a/src/Websites/Sales/src/Directory.Build.props b/src/Websites/Sales/src/Directory.Build.props index 78346dbd8f..e86d335b81 100644 --- a/src/Websites/Sales/src/Directory.Build.props +++ b/src/Websites/Sales/src/Directory.Build.props @@ -1,41 +1,25 @@ - BlazorServer - - - SSR - - - $(DefineConstants);BlazorWebAssembly - $(DefineConstants);BlazorServer - $(DefineConstants);SSR - $(DefineConstants);Static - - 11.0 enable enable - + true + $(NoWarn);CS1998;CS1591 + 12.0 en - false - $(DefineConstants);MultilingualEnabled - - - -