Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,38 @@
# Changelog

## 2026-02-11 (Loader Follow-up)

- PR: [Techinterview-space/frontend#119](https://github.com/Techinterview-space/frontend/pull/119)
- Branch: `codex/loader-fix-lighthouse-followup`
- Date: `2026-02-11`

### Summary

Follow-up fix for the new shared loader behavior and a production Lighthouse snapshot after the latest merged PR.

### Maintainer Notes

- Changed shared loading spinner defaults:
- `app-loading-spinner` now uses spinner-only mode by default.
- GIF loading is opt-in via `[showGif]="true"`.
- On GIF load failure, component now keeps spinner visible instead of hiding it.
- Updated unit tests to cover:
- default non-GIF behavior
- delayed GIF behavior when enabled
- Production Lighthouse snapshot (captured on `2026-02-11`):
- `/salaries` mobile: Performance `47`, Accessibility `100`, Best Practices `93`, SEO `93`
- `/salaries` desktop: Performance `99`, Accessibility `100`, Best Practices `100`, SEO `90`
- `/` mobile: Performance `60`, Accessibility `97`, Best Practices `93`, SEO `100`
- `/` desktop: Performance `74`, Accessibility `98`, Best Practices `93`, SEO `100`
- Key perf observation:
- delayed loader GIF still shows ~4.25 MiB potential savings on `/salaries` mobile when enabled
- moving shared loaders to spinner-only by default avoids this regression for route loading states

### Validation Performed

- `npx ng test --no-watch --browsers ChromiumNoSandbox --include=src/app/shared/components/loading-spinner/loading-spinner.component.spec.ts`
- `npm run build-prod`

## 2026-02-11

- PR: [Techinterview-space/frontend#118](https://github.com/Techinterview-space/frontend/pull/118)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
[src]="loadingUrl"
[alt]="loadingAlt"
(load)="onGifLoaded()"
(error)="onGifLoaded()"
(error)="onGifLoadFailed()"
title="Вертимся как можем и загружаем данные..."
/>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,21 @@ describe("LoadingSpinnerComponent", () => {
expect(component).toBeTruthy();
});

it("delays gif request until threshold", fakeAsync(() => {
it("does not request gif by default", fakeAsync(() => {
component.ngOnDestroy();
component.showGif = false;
component.loadingUrl = "";

component.ngOnInit();
tick(2000);
expect(component.loadingUrl).toBe("");

component.ngOnDestroy();
}));

it("delays gif request until threshold when enabled", fakeAsync(() => {
component.ngOnDestroy();
component.showGif = true;
component.delayMs = 500;
component.loadingUrl = "";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ export class LoadingSpinnerComponent implements OnInit, OnDestroy {
@Input()
style = "spinner-border-lg";

@Input()
showGif = false;

@Input()
delayMs = 750;

Expand All @@ -24,6 +27,10 @@ export class LoadingSpinnerComponent implements OnInit, OnDestroy {
private delayTimerId: ReturnType<typeof setTimeout> | null = null;

ngOnInit(): void {
if (!this.showGif) {
return;
}

const now = new Date();
const isOdd = now.getHours() % 2 === 1;
const selectedGif = isOdd
Expand All @@ -32,10 +39,11 @@ export class LoadingSpinnerComponent implements OnInit, OnDestroy {
const selectedAlt = isOdd ? "Loading cat GIF" : "Loading dog GIF";

// Delay heavy GIF loading so fast responses avoid a multi-MB transfer.
const delay = Math.max(0, this.delayMs);
this.delayTimerId = setTimeout(() => {
this.loadingUrl = selectedGif;
this.loadingAlt = selectedAlt;
}, this.delayMs);
}, delay);
}

ngOnDestroy(): void {
Expand All @@ -48,4 +56,9 @@ export class LoadingSpinnerComponent implements OnInit, OnDestroy {
onGifLoaded(): void {
this.showPreloader = false;
}

onGifLoadFailed(): void {
this.loadingUrl = "";
this.showPreloader = true;
}
}