Skip to content

Commit d4ba70c

Browse files
markgohoclaude
andcommitted
Improve cancel button UX on profile page and fix secondary button focus contrast
Cancel button now shows "No changes to discard." when clicked with no pending changes, instead of silently doing nothing. Also fixes a contrast issue where secondary buttons got a teal background on focus (via .button:focus) without changing text color, resulting in teal-on-teal. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent be2c6e1 commit d4ba70c

4 files changed

Lines changed: 34 additions & 11 deletions

File tree

members/src/app/edit-profile/edit-profile.html

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,13 @@ <h2>Profile Setup Required</h2>
2424
} @else if (profileResource.hasValue()) {
2525
@let profile = profileResource.value();
2626
<form [formGroup]="profileForm" (ngSubmit)="onSubmit()" class="profile-form">
27+
<!-- Info Message -->
28+
@if (infoMessage()) {
29+
<div class="form__info-message">
30+
{{ infoMessage() }}
31+
</div>
32+
}
33+
2734
<!-- Success Message -->
2835
@if (successMessage()) {
2936
<div class="form__success-message">
@@ -213,14 +220,7 @@ <h2>Profile Setup Required</h2>
213220

214221
<!-- Form Actions -->
215222
<div class="form-actions">
216-
<button
217-
type="button"
218-
class="button button--secondary"
219-
(click)="onCancel()"
220-
[disabled]="loading()"
221-
>
222-
Cancel
223-
</button>
223+
<button type="button" class="button button--secondary" (click)="onCancel()">Cancel</button>
224224
<button
225225
type="submit"
226226
class="button button--primary"

members/src/app/edit-profile/edit-profile.spec.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ describe('EditProfile', () => {
230230
});
231231

232232
describe('cancel functionality', () => {
233-
it('should reset form to original values when cancel is clicked', async () => {
233+
it('should reset form to original values when cancel is clicked after changes', async () => {
234234
const { user } = await setup();
235235

236236
const titleInput = screen.getByLabelText('Name *') as HTMLInputElement;
@@ -243,19 +243,32 @@ describe('EditProfile', () => {
243243
expect(titleInput.value).toBe('Jane Doe');
244244
});
245245

246-
it('should clear error messages when cancel is clicked', async () => {
246+
it('should clear error messages when cancel is clicked after changes', async () => {
247247
const { user } = await setup({ updateShouldFail: true });
248248

249249
const submitButton = screen.getByRole('button', { name: 'Save Profile' });
250250
await user.click(submitButton);
251251

252252
expect(await screen.findByText(/failed to update profile/i)).toBeVisible();
253253

254+
// Make a change so the form is dirty, then cancel
255+
const titleInput = screen.getByLabelText('Name *');
256+
await user.type(titleInput, 'x');
257+
254258
const cancelButton = screen.getByRole('button', { name: 'Cancel' });
255259
await user.click(cancelButton);
256260

257261
expect(screen.queryByText(/failed to update profile/i)).not.toBeInTheDocument();
258262
});
263+
264+
it('should show info message when cancel is clicked with no changes', async () => {
265+
const { user } = await setup();
266+
267+
const cancelButton = screen.getByRole('button', { name: 'Cancel' });
268+
await user.click(cancelButton);
269+
270+
expect(screen.getByText('No changes to discard.')).toBeVisible();
271+
});
259272
});
260273

261274
describe('profile image', () => {

members/src/app/edit-profile/edit-profile.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export class EditProfile {
3030
protected loading = signal(false);
3131
protected errorMessage = signal('');
3232
protected successMessage = signal('');
33+
protected infoMessage = signal('');
3334

3435
private autoRetryCount = 0;
3536

@@ -66,6 +67,7 @@ export class EditProfile {
6667
this.loading.set(true);
6768
this.errorMessage.set('');
6869
this.successMessage.set('');
70+
this.infoMessage.set('');
6971

7072
try {
7173
const profileData = extractProfileData(this.profileForm);
@@ -81,13 +83,18 @@ export class EditProfile {
8183
}
8284
}
8385

84-
protected onCancel() {
86+
protected onCancel(): void {
87+
if (!this.profileForm.dirty) {
88+
this.infoMessage.set('No changes to discard.');
89+
return;
90+
}
8591
const profile = this.profile();
8692
if (profile) {
8793
initializeEditProfileForm(this.profileForm, profile);
8894
}
8995
this.errorMessage.set('');
9096
this.successMessage.set('');
97+
this.infoMessage.set('');
9198
}
9299

93100
protected getTagUrl(tag: string): string {

members/src/styles.scss

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,9 @@ main h1 {
311311
.button:focus {
312312
background: var(--teal-600);
313313
}
314+
.button--secondary:focus:not(:focus-visible) {
315+
background-color: transparent;
316+
}
314317
.button-small {
315318
font-size: var(--step-0);
316319
}

0 commit comments

Comments
 (0)