Skip to content

Commit 28f11bb

Browse files
authored
Optimize user management interface for mobile devices with PWA support (#775)
### Summary & Motivation This change transforms the user management interface into a mobile-first experience with Progressive Web App (PWA) capabilities. The changes ensure that the application feels native on mobile devices while maintaining full functionality. Changes include: - Added PWA manifest and service worker for installable app experience - Implemented full-screen dialogs and modals on mobile devices - Added infinite scroll for user lists on mobile with optimized performance - Integrated iOS-specific optimizations: - Dynamic Island support - Safe area handling for notched devices - Viewport fit adjustments - Enhanced touch interactions with axis locking for smooth scrolling - Converted table layouts to responsive cards on mobile - Fixed mobile menu overlays and navigation - Added keyboard navigation support for accessibility - Optimized avatar upload and image handling for mobile - Improved form layouts and input fields for touch devices - Added "Add to Home Screen" prompt component - Implemented responsive breakpoints throughout the UI - Enhanced modal positioning to respect safe areas - Added mobile-specific scroll behavior improvements - Optimized button sizes and touch targets for mobile - Fixed dropdown and select components for mobile viewports - Added proper viewport meta tags for mobile optimization - Improved loading states and animations for mobile performance The motivation is to provide administrators with a seamless experience when managing users on mobile devices, whether accessing through a browser or as an installed PWA. This enables on-the-go administration without compromising functionality or user experience. ### Checklist - [x] I have added tests, or done manual regression tests - [x] I have updated the documentation, if necessary
2 parents 58f9519 + 4ad3774 commit 28f11bb

40 files changed

+2180
-839
lines changed

application/AppGateway/appsettings.json

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,50 @@
1111
"AllowedHosts": "*",
1212
"ReverseProxy": {
1313
"Routes": {
14+
"favicon": {
15+
"ClusterId": "account-management-static",
16+
"Match": {
17+
"Path": "/favicon.ico"
18+
},
19+
"Transforms": [
20+
{
21+
"ResponseHeader": "Cache-Control",
22+
"Set": "public, max-age=604800"
23+
},
24+
{
25+
"ResponseHeader": "Content-Type",
26+
"Set": "image/x-icon"
27+
}
28+
]
29+
},
30+
"apple-touch-icon": {
31+
"ClusterId": "account-management-static",
32+
"Match": {
33+
"Path": "/apple-touch-icon.png"
34+
},
35+
"Transforms": [
36+
{
37+
"ResponseHeader": "Cache-Control",
38+
"Set": "public, max-age=604800"
39+
}
40+
]
41+
},
42+
"manifest": {
43+
"ClusterId": "account-management-static",
44+
"Match": {
45+
"Path": "/manifest.json"
46+
},
47+
"Transforms": [
48+
{
49+
"ResponseHeader": "Cache-Control",
50+
"Set": "public, max-age=604800"
51+
},
52+
{
53+
"ResponseHeader": "Content-Type",
54+
"Set": "application/manifest+json"
55+
}
56+
]
57+
},
1458
"root": {
1559
"ClusterId": "account-management-api",
1660
"Match": {

application/account-management/WebApp/federated-modules/common/SupportDialog.tsx

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { t } from "@lingui/core/macro";
22
import { Button } from "@repo/ui/components/Button";
33
import { Dialog, DialogTrigger } from "@repo/ui/components/Dialog";
4+
import { DialogContent, DialogFooter, DialogHeader } from "@repo/ui/components/DialogFooter";
45
import { Heading } from "@repo/ui/components/Heading";
56
import { Modal } from "@repo/ui/components/Modal";
67
import { MailIcon, XIcon } from "lucide-react";
@@ -15,26 +16,27 @@ export function SupportDialog({ children }: Readonly<SupportDialogProps>) {
1516
<DialogTrigger>
1617
{children}
1718
<Modal isDismissable={true} zIndex="high">
18-
<Dialog className="max-w-lg">
19+
<Dialog className="sm:max-w-lg">
1920
{({ close }) => (
2021
<>
2122
<XIcon onClick={close} className="absolute top-2 right-2 h-10 w-10 cursor-pointer p-2 hover:bg-muted" />
22-
<Heading slot="title" className="text-2xl">
23-
{t`Contact support`}
24-
</Heading>
25-
<p className="text-muted-foreground text-sm">{t`Need help? Our support team is here to assist you.`}</p>
26-
<div className="mt-4 flex flex-col gap-4">
23+
<DialogHeader description={t`Need help? Our support team is here to assist you.`}>
24+
<Heading slot="title" className="text-2xl">
25+
{t`Contact support`}
26+
</Heading>
27+
</DialogHeader>
28+
<DialogContent className="flex flex-col gap-4">
2729
<div className="flex items-center gap-3 rounded-lg border border-input bg-input-background p-4 opacity-50">
2830
<MailIcon className="h-5 w-5 text-muted-foreground" />
2931
<a href="mailto:support@platformplatform.net" className="text-primary hover:underline">
3032
support@platformplatform.net
3133
</a>
3234
</div>
3335
<p className="text-muted-foreground text-sm">{t`Feel free to reach out with any questions or issues you may have.`}</p>
34-
<div className="mt-6 flex justify-end gap-4">
35-
<Button onPress={close}>{t`Close`}</Button>
36-
</div>
37-
</div>
36+
</DialogContent>
37+
<DialogFooter>
38+
<Button onPress={close}>{t`Close`}</Button>
39+
</DialogFooter>
3840
</>
3941
)}
4042
</Dialog>

application/account-management/WebApp/federated-modules/common/ThemeModeSelector.tsx

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,20 @@ enum ThemeMode {
1515
Dark = "dark"
1616
}
1717

18+
function updateThemeColorMeta() {
19+
requestAnimationFrame(() => {
20+
const root = document.documentElement;
21+
const computedStyle = window.getComputedStyle(root);
22+
const backgroundHsl = computedStyle.getPropertyValue("--background").trim();
23+
const backgroundColor = backgroundHsl ? `hsl(${backgroundHsl.replace(/\s+/g, ", ")})` : "#000000";
24+
25+
const themeColorMetas = document.querySelectorAll('meta[name="theme-color"]');
26+
themeColorMetas.forEach((meta) => {
27+
meta.setAttribute("content", backgroundColor);
28+
});
29+
});
30+
}
31+
1832
export default function ThemeModeSelector({
1933
variant = "icon",
2034
onAction
@@ -52,6 +66,8 @@ export default function ThemeModeSelector({
5266
}
5367
}
5468

69+
updateThemeColorMeta();
70+
5571
// Listen for storage changes from other tabs/components
5672
const handleStorageChange = (e: StorageEvent) => {
5773
if (e.key === THEME_MODE_KEY && e.newValue) {
@@ -109,6 +125,8 @@ export default function ThemeModeSelector({
109125
}
110126
}
111127

128+
updateThemeColorMeta();
129+
112130
// Dispatch event to notify other components
113131
window.dispatchEvent(new CustomEvent("theme-mode-changed", { detail: newMode }));
114132

@@ -157,7 +175,11 @@ export default function ThemeModeSelector({
157175
</div>
158176
</Button>
159177
)}
160-
<Menu onAction={handleThemeChange} aria-label={t`Change theme`} placement="bottom">
178+
<Menu
179+
onAction={handleThemeChange}
180+
aria-label={t`Change theme`}
181+
placement={variant === "mobile-menu" ? "bottom end" : "bottom"}
182+
>
161183
<MenuItem id={ThemeMode.System} textValue="System">
162184
<div className="flex items-center gap-2">
163185
{window.matchMedia("(prefers-color-scheme: dark)").matches ? (

0 commit comments

Comments
 (0)