Skip to content

Commit 60f93d5

Browse files
CopilotPhantomDave
andcommitted
Refactor: Extract validation helper, remove console spies, share widget names constant
Co-authored-by: PhantomDave <34485699+PhantomDave@users.noreply.github.com>
1 parent c338261 commit 60f93d5

5 files changed

Lines changed: 30 additions & 62 deletions

File tree

PhantomDave.BankTracking.Api/Types/Mutations/DashboardWidgetMutations.cs

Lines changed: 20 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -38,35 +38,8 @@ public async Task<DashboardWidgetType> AddWidget(
3838
.Build());
3939
}
4040

41-
string? title = null;
42-
if (input.Title is not null)
43-
{
44-
var trimmedTitle = input.Title.Trim();
45-
if (string.IsNullOrEmpty(trimmedTitle))
46-
{
47-
throw new GraphQLException(
48-
ErrorBuilder.New()
49-
.SetMessage("Widget title cannot be empty or whitespace.")
50-
.SetCode("BAD_USER_INPUT")
51-
.Build());
52-
}
53-
title = trimmedTitle;
54-
}
55-
56-
string? subtitle = null;
57-
if (input.Subtitle is not null)
58-
{
59-
var trimmedSubtitle = input.Subtitle.Trim();
60-
if (string.IsNullOrEmpty(trimmedSubtitle))
61-
{
62-
throw new GraphQLException(
63-
ErrorBuilder.New()
64-
.SetMessage("Widget subtitle cannot be empty or whitespace.")
65-
.SetCode("BAD_USER_INPUT")
66-
.Build());
67-
}
68-
subtitle = trimmedSubtitle;
69-
}
41+
var title = ValidateAndTrimString(input.Title, "title");
42+
var subtitle = ValidateAndTrimString(input.Subtitle, "subtitle");
7043

7144
var widget = new DashboardWidget
7245
{
@@ -160,30 +133,12 @@ public async Task<DashboardWidgetType> UpdateWidget(
160133

161134
if (input.Title is not null)
162135
{
163-
var trimmedTitle = input.Title.Trim();
164-
if (string.IsNullOrEmpty(trimmedTitle))
165-
{
166-
throw new GraphQLException(
167-
ErrorBuilder.New()
168-
.SetMessage("Widget title cannot be empty or whitespace.")
169-
.SetCode("BAD_USER_INPUT")
170-
.Build());
171-
}
172-
widget.Title = trimmedTitle;
136+
widget.Title = ValidateAndTrimString(input.Title, "title");
173137
}
174138

175139
if (input.Subtitle is not null)
176140
{
177-
var trimmedSubtitle = input.Subtitle.Trim();
178-
if (string.IsNullOrEmpty(trimmedSubtitle))
179-
{
180-
throw new GraphQLException(
181-
ErrorBuilder.New()
182-
.SetMessage("Widget subtitle cannot be empty or whitespace.")
183-
.SetCode("BAD_USER_INPUT")
184-
.Build());
185-
}
186-
widget.Subtitle = trimmedSubtitle;
141+
widget.Subtitle = ValidateAndTrimString(input.Subtitle, "subtitle");
187142
}
188143

189144
if (input.Config is not null)
@@ -230,4 +185,20 @@ public async Task<bool> RemoveWidget(
230185

231186
return true;
232187
}
188+
189+
private static string? ValidateAndTrimString(string? value, string fieldName)
190+
{
191+
if (value is null) return null;
192+
193+
var trimmed = value.Trim();
194+
if (string.IsNullOrEmpty(trimmed))
195+
{
196+
throw new GraphQLException(
197+
ErrorBuilder.New()
198+
.SetMessage($"Widget {fieldName} cannot be empty or whitespace.")
199+
.SetCode("BAD_USER_INPUT")
200+
.Build());
201+
}
202+
return trimmed;
203+
}
233204
}

frontend/src/app/components/dashboards/dashboard-component/dashboard-component.component.spec.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@ describe('DashboardComponent', () => {
6060
});
6161

6262
it('should show error snackbar if widget creation fails', () => {
63-
spyOn(console, 'error'); // Suppress console output in tests
6463
const invalidWidgetType = 'INVALID_TYPE' as WidgetType;
6564

6665
component.onWidgetSelected(invalidWidgetType);
@@ -69,7 +68,6 @@ describe('DashboardComponent', () => {
6968
});
7069

7170
it('should not add widget to list if creation fails', () => {
72-
spyOn(console, 'error'); // Suppress console output in tests
7371
const invalidWidgetType = 'INVALID_TYPE' as WidgetType;
7472
const initialWidgetCount = component.widgets().length;
7573

frontend/src/app/components/dashboards/dashboard-component/dashboard-component.component.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import { WidgetType } from '../../../../generated/graphql';
1919
import { Widget } from '../../../models/dashboards/gridster-item';
2020
import { WidgetFactory } from '../widgets/widget-factory';
2121
import { SnackbarService } from '../../../shared/services/snackbar.service';
22+
import { WIDGET_DISPLAY_NAMES } from '../../../constants/widget-names';
2223

2324
@Component({
2425
standalone: true,
@@ -154,11 +155,7 @@ export class DashboardComponent implements OnInit {
154155
const widget = WidgetFactory.createWidget(widgetType);
155156
this.widgets.set([...this.widgets(), widget]);
156157

157-
const widgetNames: Record<WidgetType, string> = {
158-
[WidgetType.NET_GRAPH]: 'Net Graph',
159-
[WidgetType.CURRENT_BALANCE]: 'Remaining Budget',
160-
};
161-
const widgetName = widgetNames[widgetType] ?? String(widgetType);
158+
const widgetName = WIDGET_DISPLAY_NAMES[widgetType] ?? String(widgetType);
162159
this.snackbarService.success(`Added ${widgetName} widget to dashboard.`);
163160
} catch (error) {
164161
this.snackbarService.error('Failed to add widget to dashboard.');

frontend/src/app/components/dashboards/dashboard-drawer-component/dashboard-drawer-component.component.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { MatIconButton } from '@angular/material/button';
44
import { MatIcon } from '@angular/material/icon';
55
import { FlexComponent } from '../../ui-library/flex-component/flex-component';
66
import { WidgetType } from '../../../../generated/graphql';
7+
import { WIDGET_DISPLAY_NAMES } from '../../../constants/widget-names';
78

89
@Component({
910
selector: 'app-dashboard-drawer-component',
@@ -17,14 +18,9 @@ export class DashboardDrawerComponent {
1718
closed = output<void>();
1819
widgetSelected = output<WidgetType>();
1920

20-
private static readonly WIDGET_DISPLAY_NAMES: Record<WidgetType, string> = {
21-
[WidgetType.NET_GRAPH]: 'Net Graph',
22-
[WidgetType.CURRENT_BALANCE]: 'Remaining Budget',
23-
};
24-
2521
readonly availableWidgets = Object.values(WidgetType).map((type) => ({
2622
type,
27-
name: DashboardDrawerComponent.WIDGET_DISPLAY_NAMES[type] ?? String(type),
23+
name: WIDGET_DISPLAY_NAMES[type] ?? String(type),
2824
}));
2925

3026
addWidgetToDashboard(widget: { type: WidgetType; name: string }) {
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { WidgetType } from '../../generated/graphql';
2+
3+
export const WIDGET_DISPLAY_NAMES: Record<WidgetType, string> = {
4+
[WidgetType.NET_GRAPH]: 'Net Graph',
5+
[WidgetType.CURRENT_BALANCE]: 'Remaining Budget',
6+
};

0 commit comments

Comments
 (0)