Skip to content

Commit 464a7fd

Browse files
committed
Refactor thumbnail photo handling with new component
Introduce ContactThumbnailPhoto.razor for reusable thumbnail display/editing, including required field indication. Centralize required field logic with IsRequiredField extension. Update input fields to use RequireField for consistent required status. Remove redundant thumbnail code from DetailsSection. Update project version to 2026.02.25.0153.
1 parent dfe87c0 commit 464a7fd

File tree

10 files changed

+134
-71
lines changed

10 files changed

+134
-71
lines changed

BLAZAM/BLAZAM.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<ImplicitUsings>enable</ImplicitUsings>
77
<ServerGarbageCollection>false</ServerGarbageCollection>
88
<AssemblyVersion>1.5.1</AssemblyVersion>
9-
<Version>2026.02.25.0040</Version>
9+
<Version>2026.02.25.0153</Version>
1010
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
1111
<RootNamespace>BLAZAM</RootNamespace>
1212
<GenerateDocumentationFile>True</GenerateDocumentationFile>

BLAZAMDatabase/Helpers/DatabaseHelpers.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,14 @@ public static bool IsEditableField (this DirectoryTemplate template, IActiveDire
3737
else
3838
return template.EffectiveFieldValues.Any(f => f.CustomField.FieldName == field.FieldName && f.Editable);
3939
}
40+
41+
public static bool IsRequiredField (this DirectoryTemplate template, IActiveDirectoryField field)
42+
{
43+
if (field is ActiveDirectoryField)
44+
return template.EffectiveFieldValues.Any(f => f.Field?.FieldName == field.FieldName && f.Required);
45+
else
46+
return template.EffectiveFieldValues.Any(f => f.CustomField.FieldName == field.FieldName && f.Required);
47+
}
4048
public static long GetMembersHash(this IEnumerable<AppUser> members)
4149
{
4250
long hash = 0;

BLAZAMGui/UI/DirectoryModelComponentElement.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,21 @@ protected bool ShowField(IActiveDirectoryField field)
5151
}
5252
}
5353

54+
protected bool RequireField(IActiveDirectoryField field)
55+
{
56+
if (Disabled)
57+
{
58+
return false;
59+
}
60+
if (Template == null)
61+
{
62+
return false;
63+
}
64+
else
65+
{
66+
return !IsAdmin && !Template.IsRequiredField(field);
67+
}
68+
}
5469
protected bool DisableField(IActiveDirectoryField field)
5570
{
5671
if(Disabled)

BLAZAMGui/UI/Users/ConfirmNewUser.razor

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,11 @@
1111
<AppPageTitle>@AppLocalization[Lang.Confirm_User_Creation]</AppPageTitle>
1212

1313

14-
14+
@if (DirectoryTemplate.InTemplate(ActiveDirectoryFields.Thumbnail))
15+
{
16+
<ContactThumbnailPhoto Contact=Contact
17+
Disabled=true/>
18+
}
1519

1620
<MudTextField Label="@AppLocalization[Lang.OU]"
1721
Value="@Contact.OU.ToPrettyOu()"
@@ -43,9 +47,6 @@
4347
Value="@User.NewPassword.ToPlainText()"
4448
Disabled=true />
4549

46-
<MudTextField Label="@AppLocalization[Lang.Email_Address]"
47-
Value="@Contact.Email"
48-
Disabled=true />
4950
<CascadingValue Value="GroupableEntry">
5051
<CascadingValue Value="Entry">
5152
<CascadingValue Value="DirectoryTemplate">
@@ -54,13 +55,7 @@
5455
<ContactInfoSection Disabled=true />
5556

5657

57-
<ProfileSection Disabled=true />
58-
59-
60-
61-
62-
63-
58+
<ProfileSection Disabled=true />
6459

6560

6661
<ViewSection Title=@AppLocalization[Lang.Groups]>
@@ -73,6 +68,7 @@
7368
}
7469

7570
</ViewSection>
71+
7672
@if (GroupableEntry.CanReadAnyCustomFields && CustomFields != null && CustomFields.Count > 0)
7773
{
7874
<ViewSection Title=@AppLocalization[Lang.Additional_Fields]>
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
@inherits DirectoryModelComponent
2+
<MudCard Elevation="2"
3+
Style="width:fit-content;height:fit-content"
4+
Class="relative mx-auto d-block p-1 mb-5"
5+
@onmouseenter=@(() => { showRemoveThumbnail = true; })
6+
@onmouseleave=@(() => { showRemoveThumbnail = false; })>
7+
@if (Contact?.ThumbnailPhoto == null)
8+
{
9+
@if (Required)
10+
{
11+
<MudText Style="position:absolute !important;padding:2px;top:5px;right:5px"
12+
Color=Color.Error>*</MudText>
13+
}
14+
}
15+
@if (Contact?.ThumbnailPhoto != null)
16+
{
17+
<Base64Image Style="max-height:150px;max-width:150px;" Data="Contact.ThumbnailPhoto.ResizeRawImage(150)" />
18+
@if (!Disabled && showRemoveThumbnail && Contact.CanEditField(ActiveDirectoryFields.Thumbnail))
19+
{
20+
21+
<MudIconButton OnClick=RemoveThumbnail
22+
Style="position:absolute !important;width:40px;height:40px;padding:2px;top:10px;left:10px"
23+
Color=Color.Error
24+
Icon="@Icons.Material.Filled.Delete" />
25+
}
26+
@if (Required)
27+
{
28+
<MudText Style="position:absolute !important;padding:2px;top:5px;left:5px">*</MudText>
29+
}
30+
31+
}
32+
else if (User != null)
33+
{
34+
<MudIcon Style="height:150px;width:150px;" Icon="@Icons.Material.Filled.Person" />
35+
36+
}
37+
else if (Contact != null)
38+
{
39+
<MudIcon Style="height:150px;width:150px;" Icon="@Icons.Material.Filled.Contacts" />
40+
41+
}
42+
@if (!Disabled && showRemoveThumbnail && GroupableEntry?.CanEditField(ActiveDirectoryFields.Thumbnail) == true)
43+
{
44+
<MudIconButton OnClick=@(() => { _uploadThumbnailModal?.ShowAsync(); })
45+
Style="position:absolute !important;width:40px;height:40px;padding:2px;top:10px;right:10px"
46+
Color=Color.Primary
47+
Icon="@Icons.Material.Filled.Upload" />
48+
}
49+
50+
</MudCard>
51+
<AppModal Color="Color.Dark"
52+
Title=@AppLocalization[Lang.Upload_Thumbnail_Photo]
53+
@ref=@_uploadThumbnailModal>
54+
<UploadThumbnailModalContent DirectoryEntry="User" />
55+
</AppModal>
56+
@code {
57+
AppModal? _uploadThumbnailModal;
58+
bool showRemoveThumbnail = false;
59+
60+
[Parameter]
61+
public bool Disabled{ get; set; }
62+
63+
[Parameter]
64+
public bool Required { get; set; }
65+
66+
void RemoveThumbnail()
67+
{
68+
69+
Contact.ThumbnailPhoto = null;
70+
SnackBarService.Warning(GroupableEntry.DisplayName + " will have their thumbnail deleted on save.");
71+
72+
73+
}
74+
}

BLAZAMGui/UI/Users/NewTemplateUser.razor

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@
1818
</MudAlert>
1919
}
2020
}
21+
@if (InDirectoryTemplate(ActiveDirectoryFields.Thumbnail)){
22+
<ContactThumbnailPhoto Contact=Contact
23+
Required=@(DirectoryTemplate.IsRequiredField(ActiveDirectoryFields.Thumbnail))
24+
Disabled=@(!IsAdmin && !DirectoryTemplate.IsEditableField(ActiveDirectoryFields.Thumbnail)) />
25+
}
2126
@if (InDirectoryTemplate(ActiveDirectoryFields.LogonHours) ||
2227
InDirectoryTemplate(ActiveDirectoryFields.LogOnTo) ||
2328
InDirectoryTemplate(ActiveDirectoryFields.AccountExpires)
@@ -91,7 +96,7 @@
9196
Label="@AppLocalization[Lang.Site]"
9297
@bind-Value="@Contact.Site"
9398
Disabled=@(!IsAdmin && !DirectoryTemplate.IsEditableField(ActiveDirectoryFields.Site))
94-
Required=@(IsRequiredTemplateField(ActiveDirectoryFields.Site)) />
99+
Required=@(DirectoryTemplate.IsRequiredField(ActiveDirectoryFields.Site)) />
95100

96101
}
97102

@@ -167,15 +172,7 @@
167172
return DirectoryTemplate.EffectiveFieldValues.Any(f => (f.Field != null && f.Field.FieldName == field.FieldName) || (f.CustomField != null && f.CustomField.FieldName == field.FieldName));
168173
}
169174

170-
bool IsRequiredTemplateField(IActiveDirectoryField field)
171-
{
172-
173175

174-
if (field is ActiveDirectoryField)
175-
return DirectoryTemplate.EffectiveFieldValues.Any(f => f.Field?.FieldName == field.FieldName && f.Required);
176-
else
177-
return DirectoryTemplate.EffectiveFieldValues.Any(f => f.CustomField.FieldName == field.FieldName && f.Required);
178-
}
179176

180177
bool ValidateCustomField(DirectoryTemplateFieldValue field)
181178
{

BLAZAMGui/UI/Users/Sections/ContactInfoSection.razor

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
<DynamicMudInput T=string
99
Label="@AppLocalization[Lang.Telephone_Number]"
1010
@bind-Value="@Contact.TelephoneNumber"
11+
Required=@(RequireField(ActiveDirectoryFields.TelephoneNumber))
1112
Disabled=@(DisableField(ActiveDirectoryFields.TelephoneNumber)) />
1213

1314
}
@@ -16,6 +17,7 @@
1617
<DynamicMudInput T=string
1718
Label="@AppLocalization[Lang.Home_Phone]"
1819
@bind-Value="@Contact.HomePhone"
20+
Required=@(RequireField(ActiveDirectoryFields.HomePhone))
1921
Disabled=@(DisableField(ActiveDirectoryFields.HomePhone)) />
2022

2123
}
@@ -24,34 +26,39 @@
2426
<DynamicMudInput T=string
2527
Label="@AppLocalization[Lang.Street_Address]"
2628
@bind-Value="@Contact.StreetAddress"
29+
Required=@(RequireField(ActiveDirectoryFields.StreetAddress))
2730
Disabled=@(DisableField(ActiveDirectoryFields.StreetAddress)) />
2831
}
2932
@if (ShowField(ActiveDirectoryFields.POBox))
3033
{
3134
<DynamicMudInput T=string
3235
Label="@AppLocalization[Lang.PO_Box]"
3336
@bind-Value="@Contact.POBox"
37+
Required=@(RequireField(ActiveDirectoryFields.POBox))
3438
Disabled=@(DisableField(ActiveDirectoryFields.POBox)) />
3539
}
3640
@if (ShowField(ActiveDirectoryFields.City))
3741
{
3842
<DynamicMudInput T=string
3943
Label="@AppLocalization[Lang.City]"
4044
@bind-Value="@Contact.City"
45+
Required=@(RequireField(ActiveDirectoryFields.City))
4146
Disabled=@(DisableField(ActiveDirectoryFields.City)) />
4247
}
4348
@if (ShowField(ActiveDirectoryFields.State))
4449
{
4550
<DynamicMudInput T=string
4651
Label="@AppLocalization[Lang.State]"
4752
@bind-Value="@Contact.State"
53+
Required=@(RequireField(ActiveDirectoryFields.State))
4854
Disabled=@(DisableField(ActiveDirectoryFields.State)) />
4955
}
5056
@if (ShowField(ActiveDirectoryFields.PostalCode))
5157
{
5258
<DynamicMudInput T=string
5359
Label="@AppLocalization[Lang.Zip_Code]"
5460
@bind-Value="@Contact.Zip"
61+
Required=@(RequireField(ActiveDirectoryFields.PostalCode))
5562
Disabled=@(DisableField(ActiveDirectoryFields.PostalCode)) />
5663
}
5764

BLAZAMGui/UI/Users/Sections/DetailsSection.razor

Lines changed: 3 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -7,43 +7,7 @@
77

88
<ViewSection Title="@AppLocalization["User Details"]" Stack=true FullWidth=false>
99

10-
<MudCard Elevation="2"
11-
Style="width:fit-content;height:fit-content"
12-
Class="relative mx-auto d-block p-1 mb-5"
13-
@onmouseenter=@(()=>{showRemoveThumbnail=true;})
14-
@onmouseleave=@(()=>{showRemoveThumbnail=false;})>
15-
16-
@if (Contact?.ThumbnailPhoto != null)
17-
{
18-
<Base64Image Style="max-height:150px;max-width:150px;" Data="Contact.ThumbnailPhoto.ResizeRawImage(150)" />
19-
@if (showRemoveThumbnail && Contact.CanEditField(ActiveDirectoryFields.Thumbnail))
20-
{
21-
22-
<MudIconButton OnClick=RemoveThumbnail
23-
Style="position:absolute !important;width:40px;height:40px;padding:2px;top:10px;left:10px"
24-
Color=Color.Error
25-
Icon="@Icons.Material.Filled.Delete" />
26-
}
27-
28-
}
29-
else if (User != null)
30-
{
31-
<MudIcon Style="height:150px;width:150px;" Icon="@Icons.Material.Filled.Person" />
32-
33-
}
34-
else if (Contact != null)
35-
{
36-
<MudIcon Style="height:150px;width:150px;" Icon="@Icons.Material.Filled.Contacts" />
37-
38-
}
39-
@if (showRemoveThumbnail && GroupableEntry?.CanEditField(ActiveDirectoryFields.Thumbnail) == true)
40-
{
41-
<MudIconButton OnClick=@(()=>{UploadThumbnailModal?.ShowAsync();})
42-
Style="position:absolute !important;width:40px;height:40px;padding:2px;top:10px;right:10px"
43-
Color=Color.Primary
44-
Icon="@Icons.Material.Filled.Upload" />
45-
}
46-
</MudCard>
10+
<ContactThumbnailPhoto Contact=Contact/>
4711

4812
<MudStack Row=true>
4913
<MudText Typo="Typo.subtitle2">@AppLocalization[Lang.Created]:</MudText>
@@ -120,25 +84,14 @@
12084

12185
</ViewSection>
12286

123-
<AppModal Color="Color.Dark" Title=@AppLocalization[Lang.Upload_Thumbnail_Photo] @ref=@UploadThumbnailModal>
124-
<UploadThumbnailModalContent DirectoryEntry="User" />
125-
</AppModal>
87+
12688

12789

12890
@code {
129-
AppModal? UploadThumbnailModal { get; set; }
13091

13192

13293
[Parameter]
13394
public EventCallback AssignToClicked { get; set; }
134-
bool showRemoveThumbnail = false;
13595

136-
void RemoveThumbnail()
137-
{
138-
139-
Contact.ThumbnailPhoto = null;
140-
SnackBarService.Warning(GroupableEntry.DisplayName + " will have their thumbnail deleted on save.");
141-
142-
143-
}
96+
14497
}

BLAZAMGui/UI/Users/Sections/OrganizationSection.razor

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
<DynamicMudInput T=string
1919
Label="@AppLocalization[Lang.Description]"
2020
@bind-Value="@Contact.Description"
21+
Required=@(RequireField(ActiveDirectoryFields.Description))
22+
2123
Disabled=@(DisableField(ActiveDirectoryFields.Description)) />
2224
}
2325

@@ -26,6 +28,7 @@
2628
<DynamicMudInput T=string
2729
Label="@AppLocalization[Lang.Email_Address]"
2830
@bind-Value="@Contact.Email"
31+
Required=@(RequireField(ActiveDirectoryFields.Mail))
2932
Disabled=@(DisableField(ActiveDirectoryFields.Mail)) />
3033
}
3134

@@ -34,20 +37,23 @@
3437
<DynamicMudInput T=string
3538
Label="@AppLocalization[Lang.Employee_Id]"
3639
@bind-Value="@Contact.EmployeeId"
40+
Required=@(RequireField(ActiveDirectoryFields.EmployeeId))
3741
Disabled=@(DisableField(ActiveDirectoryFields.EmployeeId)) />
3842
}
3943
@if (ShowField(ActiveDirectoryFields.Department))
4044
{
4145
<DynamicMudInput T=string
4246
Label="@AppLocalization[Lang.Department]"
4347
@bind-Value="@Contact.Department"
48+
Required=@(RequireField(ActiveDirectoryFields.Department))
4449
Disabled=@(DisableField(ActiveDirectoryFields.Department)) />
4550
}
4651
@if (ShowField(ActiveDirectoryFields.Company))
4752
{
4853
<DynamicMudInput T=string
4954
Label="@AppLocalization[Lang.Company]"
5055
@bind-Value="@Contact.Company"
56+
Required=@(RequireField(ActiveDirectoryFields.Company))
5157
Disabled=@(DisableField(ActiveDirectoryFields.Company)) />
5258
}
5359
@if (ShowField(ActiveDirectoryFields.Manager))
@@ -56,20 +62,23 @@
5662
Label="@AppLocalization[Lang.Manager]"
5763
SelectedResult=Contact.Manager
5864
SelectedResultChanged="@((user)=>{Contact.Manager=user as IADUser;})"
65+
5966
Disabled=@(DisableField(ActiveDirectoryFields.Manager)) />
6067
}
6168
@if (ShowField(ActiveDirectoryFields.Title))
6269
{
6370
<DynamicMudInput T=string
6471
Label="@AppLocalization[Lang.Job_Title]"
6572
@bind-Value="@Contact.Title"
73+
Required=@(RequireField(ActiveDirectoryFields.Title))
6674
Disabled=@(DisableField(ActiveDirectoryFields.Title)) />
6775
}
6876
@if (ShowField(ActiveDirectoryFields.PhysicalDeliveryOffice))
6977
{
7078
<DynamicMudInput T=string
7179
Label="@AppLocalization[Lang.Office]"
7280
@bind-Value="@Contact.PhysicalDeliveryOfficeName"
81+
Required=@(RequireField(ActiveDirectoryFields.PhysicalDeliveryOffice))
7382
Disabled=@(DisableField(ActiveDirectoryFields.PhysicalDeliveryOffice)) />
7483
}
7584

0 commit comments

Comments
 (0)