-
Notifications
You must be signed in to change notification settings - Fork 0
[STU-154] Landing page UX overhaul — copy, icons, and benefits section #36
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
1ba4f90
feat: overhaul landing page UX with improved copy, portal icons, and …
BAWES 2722a47
test: add landing page smoke validation for STU-154 UX changes
BAWES 090d709
fix: resolve TS errors on PR #36 — rejection_reason query and WorkLog…
BAWES abaa17a
chore: trigger CI re-run
BAWES afbee09
chore: trigger CI [skip vercel]
BAWES 0192419
Revert "chore: trigger CI [skip vercel]"
BAWES b9a8568
fix: resolve merge conflict with main in WorkLogStaffActions type cas…
BAWES f8459e8
fix: remove certificate_title/issuer/url from PR #36 Zod schema and f…
BAWES File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,88 @@ | ||
| import { test, expect } from "@playwright/test"; | ||
|
|
||
| test.describe("Landing page smoke tests (STU-154)", () => { | ||
| test("landing page loads with hero content", async ({ page }) => { | ||
| await page.goto("/"); | ||
| await expect(page.locator("body")).toBeVisible({ timeout: 15000 }); | ||
|
|
||
| // Hero copy (changed in STU-154) | ||
| await expect(page.locator(".landingHeroCopy")).toBeVisible(); | ||
| await expect(page.locator("h1")).toHaveText("Every role gets its own workspace."); | ||
| await expect(page.locator(".landingHeroCopy .eyebrow")).toHaveText("The StudentHub platform"); | ||
| }); | ||
|
|
||
| test("hero CTA buttons render", async ({ page }) => { | ||
| await page.goto("/"); | ||
| await expect(page.locator(".landingActions")).toBeVisible(); | ||
| await expect(page.locator(".landingActions >> text=Get started")).toBeVisible(); | ||
| await expect(page.locator(".landingActions >> text=Explore portals")).toBeVisible(); | ||
| }); | ||
|
|
||
| test("platform highlights strip renders", async ({ page }) => { | ||
| await page.goto("/"); | ||
| const stats = page.locator(".landingHeroStats"); | ||
| await expect(stats).toBeVisible(); | ||
| await expect(stats).toHaveAttribute("aria-label", "Platform highlights"); | ||
| await expect(stats).toContainText("5 role-specific portals"); | ||
| await expect(stats).toContainText("Unified search & documents"); | ||
| await expect(stats).toContainText("End-to-end workflows"); | ||
| }); | ||
|
|
||
| test("portal grid renders all 5 portal cards with icons", async ({ page }) => { | ||
| await page.goto("/"); | ||
| const portalGrid = page.locator("section[aria-label='StudentHub portals']"); | ||
| await expect(portalGrid).toBeVisible(); | ||
|
|
||
| const portalLinks = portalGrid.locator("a"); | ||
| await expect(portalLinks).toHaveCount(5); | ||
|
|
||
| // Each portal card has an emoji icon (aria-hidden) | ||
| const icons = portalGrid.locator(".portalIcon"); | ||
| await expect(icons).toHaveCount(5); | ||
| for (const icon of await icons.all()) { | ||
| await expect(icon).toHaveAttribute("aria-hidden", "true"); | ||
| } | ||
| }); | ||
|
|
||
| test("benefits section renders with all cards", async ({ page }) => { | ||
| await page.goto("/"); | ||
| const benefitsSection = page.locator(".landingBenefitsSection"); | ||
| await expect(benefitsSection).toBeVisible(); | ||
| await expect(benefitsSection.locator(".eyebrow")).toHaveText("Why StudentHub"); | ||
| await expect(benefitsSection.locator("h2")).toHaveText("Built for how staffing actually works."); | ||
|
|
||
| const benefitCards = benefitsSection.locator(".benefitGrid article"); | ||
| await expect(benefitCards).toHaveCount(4); | ||
|
|
||
| await expect(benefitCards.nth(0)).toContainText("Purpose-built portals"); | ||
| await expect(benefitCards.nth(1)).toContainText("Smart candidate search"); | ||
| await expect(benefitCards.nth(2)).toContainText("End-to-end workflows"); | ||
| await expect(benefitCards.nth(3)).toContainText("Production-grade foundation"); | ||
| }); | ||
|
|
||
| test("nav renders brand and sign in link", async ({ page }) => { | ||
| await page.goto("/"); | ||
| const nav = page.locator("nav[aria-label='StudentHub public navigation']"); | ||
| await expect(nav).toBeVisible(); | ||
| await expect(nav).toContainText("StudentHub"); | ||
| await expect(nav).toContainText("Sign in"); | ||
| }); | ||
|
|
||
| test("decorative ops frame is aria-hidden", async ({ page }) => { | ||
| await page.goto("/"); | ||
| const stage = page.locator(".landingHeroStage"); | ||
| await expect(stage).toHaveAttribute("aria-hidden", "true"); | ||
| await expect(stage.locator(".landingOpsSearch")).toContainText("find talent"); | ||
| }); | ||
|
|
||
| test.describe("mobile", () => { | ||
| test.use({ viewport: { width: 390, height: 844 } }); | ||
|
|
||
| test("landing page renders on mobile without overflow", async ({ page }) => { | ||
| await page.goto("/"); | ||
| await expect(page.locator("h1")).toHaveText("Every role gets its own workspace."); | ||
| await expect(page.locator(".landingActions")).toBeVisible(); | ||
| await expect(page.locator(".landingBenefitsSection")).toBeVisible(); | ||
| }); | ||
| }); | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win
Strengthen typing to align with
portalRolesand satisfy strict mode.portalIconsis typed asRecord<string, string>, but the keys are exactly the five roles defined inportalRoles(line 36). WithnoUncheckedIndexedAccessenabled (per coding guidelines), accessingportalIcons[role]at line 108 will returnstring | undefined, requiring a runtime check or type assertion.Define a more precise type to ensure compile-time safety and eliminate the need for runtime guards.
🔒 Proposed fix to align types with portalRoles
Alternatively, use
satisfiesfor inference while retaining safety:As per coding guidelines: "Strict mode enabled — no implicit
any, no unchecked index access."📝 Committable suggestion
🤖 Prompt for AI Agents