mirror of
https://github.com/johndoe6345789/low-code-react-app-b.git
synced 2026-04-24 13:44:54 +00:00
Merge pull request #46 from johndoe6345789/codex/refactor-pwasettings-into-sections
Refactor PWASettings: externalize copy and split into sections
This commit is contained in:
@@ -1,39 +1,31 @@
|
||||
import { Card } from '@/components/ui/card'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Label } from '@/components/ui/label'
|
||||
import { Switch } from '@/components/ui/switch'
|
||||
import { Separator } from '@/components/ui/separator'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { Card } from '@/components/ui/card'
|
||||
import { Label } from '@/components/ui/label'
|
||||
import pwaSettingsCopy from '@/data/pwa-settings.json'
|
||||
import { usePWA } from '@/hooks/use-pwa'
|
||||
import { useState, useEffect } from 'react'
|
||||
import {
|
||||
Download,
|
||||
CloudArrowDown,
|
||||
Trash,
|
||||
Bell,
|
||||
WifiSlash,
|
||||
WifiHigh,
|
||||
CheckCircle,
|
||||
XCircle,
|
||||
Question
|
||||
} from '@phosphor-icons/react'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { CheckCircle, WifiHigh, WifiSlash, XCircle } from '@phosphor-icons/react'
|
||||
import { toast } from 'sonner'
|
||||
import { CacheSection } from './pwa-settings/CacheSection'
|
||||
import { InstallSection } from './pwa-settings/InstallSection'
|
||||
import { NotificationsSection } from './pwa-settings/NotificationsSection'
|
||||
import { UpdateSection } from './pwa-settings/UpdateSection'
|
||||
|
||||
export function PWASettings() {
|
||||
const {
|
||||
isInstalled,
|
||||
isInstallable,
|
||||
isOnline,
|
||||
const {
|
||||
isInstalled,
|
||||
isInstallable,
|
||||
isOnline,
|
||||
isUpdateAvailable,
|
||||
installApp,
|
||||
updateApp,
|
||||
installApp,
|
||||
updateApp,
|
||||
clearCache,
|
||||
requestNotificationPermission,
|
||||
registration
|
||||
} = usePWA()
|
||||
|
||||
|
||||
const [notificationPermission, setNotificationPermission] = useState<NotificationPermission>('default')
|
||||
const [cacheSize, setCacheSize] = useState<string>('Calculating...')
|
||||
const [cacheSize, setCacheSize] = useState<string>(pwaSettingsCopy.defaults.cacheCalculating)
|
||||
|
||||
useEffect(() => {
|
||||
if ('Notification' in window) {
|
||||
@@ -41,9 +33,9 @@ export function PWASettings() {
|
||||
}
|
||||
|
||||
if ('storage' in navigator && 'estimate' in navigator.storage) {
|
||||
navigator.storage.estimate().then(estimate => {
|
||||
navigator.storage.estimate().then((estimate) => {
|
||||
const usageInMB = ((estimate.usage || 0) / (1024 * 1024)).toFixed(2)
|
||||
setCacheSize(`${usageInMB} MB`)
|
||||
setCacheSize(`${usageInMB} ${pwaSettingsCopy.cache.storageUnit}`)
|
||||
})
|
||||
}
|
||||
}, [])
|
||||
@@ -51,99 +43,55 @@ export function PWASettings() {
|
||||
const handleInstall = async () => {
|
||||
const success = await installApp()
|
||||
if (success) {
|
||||
toast.success('App installed successfully!')
|
||||
toast.success(pwaSettingsCopy.toasts.installSuccess)
|
||||
} else {
|
||||
toast.error('Installation cancelled')
|
||||
toast.error(pwaSettingsCopy.toasts.installCancelled)
|
||||
}
|
||||
}
|
||||
|
||||
const handleUpdate = () => {
|
||||
updateApp()
|
||||
toast.info('Updating app...')
|
||||
toast.info(pwaSettingsCopy.toasts.update)
|
||||
}
|
||||
|
||||
const handleClearCache = () => {
|
||||
clearCache()
|
||||
toast.success('Cache cleared! Reloading...')
|
||||
toast.success(pwaSettingsCopy.toasts.cacheCleared)
|
||||
}
|
||||
|
||||
const handleNotificationToggle = async (enabled: boolean) => {
|
||||
if (enabled) {
|
||||
const permission = await requestNotificationPermission()
|
||||
setNotificationPermission(permission as NotificationPermission)
|
||||
|
||||
if (permission === 'granted') {
|
||||
toast.success('Notifications enabled')
|
||||
} else {
|
||||
toast.error('Notification permission denied')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const getPermissionIcon = () => {
|
||||
switch (notificationPermission) {
|
||||
case 'granted':
|
||||
return <CheckCircle size={16} className="text-accent" weight="fill" />
|
||||
case 'denied':
|
||||
return <XCircle size={16} className="text-destructive" weight="fill" />
|
||||
default:
|
||||
return <Question size={16} className="text-muted-foreground" weight="fill" />
|
||||
if (permission === 'granted') {
|
||||
toast.success(pwaSettingsCopy.toasts.notificationsEnabled)
|
||||
} else {
|
||||
toast.error(pwaSettingsCopy.toasts.notificationsDenied)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="h-full overflow-auto p-6 space-y-6">
|
||||
<div>
|
||||
<h2 className="text-2xl font-bold mb-2">PWA Settings</h2>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Configure Progressive Web App features and behavior
|
||||
</p>
|
||||
<h2 className="text-2xl font-bold mb-2">{pwaSettingsCopy.header.title}</h2>
|
||||
<p className="text-sm text-muted-foreground">{pwaSettingsCopy.header.description}</p>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-6">
|
||||
<Card className="p-6">
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold mb-1">Installation Status</h3>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Install the app for offline access and better performance
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-3">
|
||||
<Download size={20} className="text-muted-foreground" />
|
||||
<div>
|
||||
<Label className="text-base">App Installation</Label>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
{isInstalled ? 'Installed' : isInstallable ? 'Available' : 'Not available'}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
{isInstalled && (
|
||||
<Badge variant="default">Installed</Badge>
|
||||
)}
|
||||
{isInstallable && !isInstalled && (
|
||||
<Button size="sm" onClick={handleInstall}>
|
||||
Install Now
|
||||
</Button>
|
||||
)}
|
||||
{!isInstallable && !isInstalled && (
|
||||
<Badge variant="secondary">Not Available</Badge>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
<InstallSection
|
||||
isInstalled={isInstalled}
|
||||
isInstallable={isInstallable}
|
||||
onInstall={handleInstall}
|
||||
copy={pwaSettingsCopy.install}
|
||||
/>
|
||||
|
||||
<Card className="p-6">
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold mb-1">Connection Status</h3>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Current network connectivity status
|
||||
</p>
|
||||
<h3 className="text-lg font-semibold mb-1">{pwaSettingsCopy.connection.title}</h3>
|
||||
<p className="text-sm text-muted-foreground">{pwaSettingsCopy.connection.description}</p>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between">
|
||||
@@ -154,142 +102,52 @@ export function PWASettings() {
|
||||
<WifiSlash size={20} className="text-destructive" />
|
||||
)}
|
||||
<div>
|
||||
<Label className="text-base">Network Status</Label>
|
||||
<Label className="text-base">{pwaSettingsCopy.connection.label}</Label>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
{isOnline ? 'Connected to internet' : 'Working offline'}
|
||||
{isOnline ? pwaSettingsCopy.connection.status.online : pwaSettingsCopy.connection.status.offline}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<Badge variant={isOnline ? 'default' : 'destructive'}>
|
||||
{isOnline ? 'Online' : 'Offline'}
|
||||
{isOnline ? pwaSettingsCopy.connection.badge.online : pwaSettingsCopy.connection.badge.offline}
|
||||
</Badge>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
{isUpdateAvailable && (
|
||||
<Card className="p-6 border-accent">
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold mb-1">Update Available</h3>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
A new version of the app is ready to install
|
||||
</p>
|
||||
</div>
|
||||
<UpdateSection
|
||||
isUpdateAvailable={isUpdateAvailable}
|
||||
onUpdate={handleUpdate}
|
||||
copy={pwaSettingsCopy.update}
|
||||
/>
|
||||
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-3">
|
||||
<CloudArrowDown size={20} className="text-accent" />
|
||||
<div>
|
||||
<Label className="text-base">App Update</Label>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
Update now for latest features
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<Button onClick={handleUpdate}>
|
||||
Update Now
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
)}
|
||||
<NotificationsSection
|
||||
permission={notificationPermission}
|
||||
onToggle={handleNotificationToggle}
|
||||
copy={pwaSettingsCopy.notifications}
|
||||
/>
|
||||
|
||||
<CacheSection
|
||||
cacheSize={cacheSize}
|
||||
hasRegistration={Boolean(registration)}
|
||||
onClearCache={handleClearCache}
|
||||
copy={pwaSettingsCopy.cache}
|
||||
/>
|
||||
|
||||
<Card className="p-6">
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold mb-1">Notifications</h3>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Receive updates about your projects and builds
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-3">
|
||||
<Bell size={20} className="text-muted-foreground" />
|
||||
<div>
|
||||
<Label className="text-base">Push Notifications</Label>
|
||||
<div className="flex items-center gap-2">
|
||||
<p className="text-xs text-muted-foreground">
|
||||
Permission: {notificationPermission}
|
||||
</p>
|
||||
{getPermissionIcon()}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Switch
|
||||
checked={notificationPermission === 'granted'}
|
||||
onCheckedChange={handleNotificationToggle}
|
||||
disabled={notificationPermission === 'denied'}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{notificationPermission === 'denied' && (
|
||||
<div className="text-xs text-destructive bg-destructive/10 p-3 rounded-md">
|
||||
Notifications are blocked. Please enable them in your browser settings.
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
<Card className="p-6">
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold mb-1">Cache Management</h3>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Manage offline storage and cached resources
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<Separator />
|
||||
|
||||
<div className="space-y-3">
|
||||
<div className="flex items-center justify-between">
|
||||
<Label className="text-sm">Cache Size</Label>
|
||||
<span className="text-sm font-mono text-muted-foreground">{cacheSize}</span>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between">
|
||||
<Label className="text-sm">Service Worker</Label>
|
||||
<Badge variant={registration ? 'default' : 'secondary'}>
|
||||
{registration ? 'Active' : 'Inactive'}
|
||||
</Badge>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Separator />
|
||||
|
||||
<Button
|
||||
variant="destructive"
|
||||
className="w-full"
|
||||
onClick={handleClearCache}
|
||||
>
|
||||
<Trash size={16} className="mr-2" />
|
||||
Clear Cache & Reload
|
||||
</Button>
|
||||
|
||||
<p className="text-xs text-muted-foreground text-center">
|
||||
This will remove all cached files and reload the app
|
||||
</p>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
<Card className="p-6">
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold mb-1">PWA Features</h3>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Progressive Web App capabilities
|
||||
</p>
|
||||
<h3 className="text-lg font-semibold mb-1">{pwaSettingsCopy.features.title}</h3>
|
||||
<p className="text-sm text-muted-foreground">{pwaSettingsCopy.features.description}</p>
|
||||
</div>
|
||||
|
||||
<div className="grid gap-3 text-sm">
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-muted-foreground">Offline Support</span>
|
||||
<span className="text-muted-foreground">{pwaSettingsCopy.features.items.offline}</span>
|
||||
<CheckCircle size={16} className="text-accent" weight="fill" />
|
||||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-muted-foreground">Installable</span>
|
||||
<span className="text-muted-foreground">{pwaSettingsCopy.features.items.installable}</span>
|
||||
{isInstallable || isInstalled ? (
|
||||
<CheckCircle size={16} className="text-accent" weight="fill" />
|
||||
) : (
|
||||
@@ -297,11 +155,11 @@ export function PWASettings() {
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-muted-foreground">Background Sync</span>
|
||||
<span className="text-muted-foreground">{pwaSettingsCopy.features.items.backgroundSync}</span>
|
||||
<CheckCircle size={16} className="text-accent" weight="fill" />
|
||||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-muted-foreground">Push Notifications</span>
|
||||
<span className="text-muted-foreground">{pwaSettingsCopy.features.items.pushNotifications}</span>
|
||||
{'Notification' in window ? (
|
||||
<CheckCircle size={16} className="text-accent" weight="fill" />
|
||||
) : (
|
||||
@@ -309,7 +167,7 @@ export function PWASettings() {
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-muted-foreground">App Shortcuts</span>
|
||||
<span className="text-muted-foreground">{pwaSettingsCopy.features.items.shortcuts}</span>
|
||||
<CheckCircle size={16} className="text-accent" weight="fill" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
66
src/components/pwa-settings/CacheSection.tsx
Normal file
66
src/components/pwa-settings/CacheSection.tsx
Normal file
@@ -0,0 +1,66 @@
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card } from '@/components/ui/card'
|
||||
import { Label } from '@/components/ui/label'
|
||||
import { Separator } from '@/components/ui/separator'
|
||||
import { Trash } from '@phosphor-icons/react'
|
||||
|
||||
interface CacheSectionProps {
|
||||
cacheSize: string
|
||||
hasRegistration: boolean
|
||||
onClearCache: () => void
|
||||
copy: {
|
||||
title: string
|
||||
description: string
|
||||
labels: {
|
||||
size: string
|
||||
serviceWorker: string
|
||||
}
|
||||
status: {
|
||||
active: string
|
||||
inactive: string
|
||||
}
|
||||
action: {
|
||||
clear: string
|
||||
}
|
||||
helper: string
|
||||
}
|
||||
}
|
||||
|
||||
export function CacheSection({ cacheSize, hasRegistration, onClearCache, copy }: CacheSectionProps) {
|
||||
return (
|
||||
<Card className="p-6">
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold mb-1">{copy.title}</h3>
|
||||
<p className="text-sm text-muted-foreground">{copy.description}</p>
|
||||
</div>
|
||||
|
||||
<Separator />
|
||||
|
||||
<div className="space-y-3">
|
||||
<div className="flex items-center justify-between">
|
||||
<Label className="text-sm">{copy.labels.size}</Label>
|
||||
<span className="text-sm font-mono text-muted-foreground">{cacheSize}</span>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between">
|
||||
<Label className="text-sm">{copy.labels.serviceWorker}</Label>
|
||||
<Badge variant={hasRegistration ? 'default' : 'secondary'}>
|
||||
{hasRegistration ? copy.status.active : copy.status.inactive}
|
||||
</Badge>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Separator />
|
||||
|
||||
<Button variant="destructive" className="w-full" onClick={onClearCache}>
|
||||
<Trash size={16} className="mr-2" />
|
||||
{copy.action.clear}
|
||||
</Button>
|
||||
|
||||
<p className="text-xs text-muted-foreground text-center">{copy.helper}</p>
|
||||
</div>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
68
src/components/pwa-settings/InstallSection.tsx
Normal file
68
src/components/pwa-settings/InstallSection.tsx
Normal file
@@ -0,0 +1,68 @@
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card } from '@/components/ui/card'
|
||||
import { Label } from '@/components/ui/label'
|
||||
import { Download } from '@phosphor-icons/react'
|
||||
|
||||
interface InstallSectionProps {
|
||||
isInstalled: boolean
|
||||
isInstallable: boolean
|
||||
onInstall: () => void
|
||||
copy: {
|
||||
title: string
|
||||
description: string
|
||||
label: string
|
||||
status: {
|
||||
installed: string
|
||||
available: string
|
||||
notAvailable: string
|
||||
}
|
||||
badge: {
|
||||
installed: string
|
||||
notAvailable: string
|
||||
}
|
||||
action: {
|
||||
install: string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function InstallSection({ isInstalled, isInstallable, onInstall, copy }: InstallSectionProps) {
|
||||
const statusText = isInstalled
|
||||
? copy.status.installed
|
||||
: isInstallable
|
||||
? copy.status.available
|
||||
: copy.status.notAvailable
|
||||
|
||||
return (
|
||||
<Card className="p-6">
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold mb-1">{copy.title}</h3>
|
||||
<p className="text-sm text-muted-foreground">{copy.description}</p>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-3">
|
||||
<Download size={20} className="text-muted-foreground" />
|
||||
<div>
|
||||
<Label className="text-base">{copy.label}</Label>
|
||||
<p className="text-xs text-muted-foreground">{statusText}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
{isInstalled && <Badge variant="default">{copy.badge.installed}</Badge>}
|
||||
{isInstallable && !isInstalled && (
|
||||
<Button size="sm" onClick={onInstall}>
|
||||
{copy.action.install}
|
||||
</Button>
|
||||
)}
|
||||
{!isInstallable && !isInstalled && (
|
||||
<Badge variant="secondary">{copy.badge.notAvailable}</Badge>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
66
src/components/pwa-settings/NotificationsSection.tsx
Normal file
66
src/components/pwa-settings/NotificationsSection.tsx
Normal file
@@ -0,0 +1,66 @@
|
||||
import { Card } from '@/components/ui/card'
|
||||
import { Label } from '@/components/ui/label'
|
||||
import { Switch } from '@/components/ui/switch'
|
||||
import { Bell, CheckCircle, Question, XCircle } from '@phosphor-icons/react'
|
||||
|
||||
interface NotificationsSectionProps {
|
||||
permission: NotificationPermission
|
||||
onToggle: (enabled: boolean) => void
|
||||
copy: {
|
||||
title: string
|
||||
description: string
|
||||
label: string
|
||||
permissionLabel: string
|
||||
blocked: string
|
||||
}
|
||||
}
|
||||
|
||||
export function NotificationsSection({ permission, onToggle, copy }: NotificationsSectionProps) {
|
||||
const getPermissionIcon = () => {
|
||||
switch (permission) {
|
||||
case 'granted':
|
||||
return <CheckCircle size={16} className="text-accent" weight="fill" />
|
||||
case 'denied':
|
||||
return <XCircle size={16} className="text-destructive" weight="fill" />
|
||||
default:
|
||||
return <Question size={16} className="text-muted-foreground" weight="fill" />
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Card className="p-6">
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold mb-1">{copy.title}</h3>
|
||||
<p className="text-sm text-muted-foreground">{copy.description}</p>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-3">
|
||||
<Bell size={20} className="text-muted-foreground" />
|
||||
<div>
|
||||
<Label className="text-base">{copy.label}</Label>
|
||||
<div className="flex items-center gap-2">
|
||||
<p className="text-xs text-muted-foreground">
|
||||
{copy.permissionLabel} {permission}
|
||||
</p>
|
||||
{getPermissionIcon()}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Switch
|
||||
checked={permission === 'granted'}
|
||||
onCheckedChange={onToggle}
|
||||
disabled={permission === 'denied'}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{permission === 'denied' && (
|
||||
<div className="text-xs text-destructive bg-destructive/10 p-3 rounded-md">
|
||||
{copy.blocked}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
44
src/components/pwa-settings/UpdateSection.tsx
Normal file
44
src/components/pwa-settings/UpdateSection.tsx
Normal file
@@ -0,0 +1,44 @@
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card } from '@/components/ui/card'
|
||||
import { Label } from '@/components/ui/label'
|
||||
import { CloudArrowDown } from '@phosphor-icons/react'
|
||||
|
||||
interface UpdateSectionProps {
|
||||
isUpdateAvailable: boolean
|
||||
onUpdate: () => void
|
||||
copy: {
|
||||
title: string
|
||||
description: string
|
||||
label: string
|
||||
status: string
|
||||
action: string
|
||||
}
|
||||
}
|
||||
|
||||
export function UpdateSection({ isUpdateAvailable, onUpdate, copy }: UpdateSectionProps) {
|
||||
if (!isUpdateAvailable) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<Card className="p-6 border-accent">
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold mb-1">{copy.title}</h3>
|
||||
<p className="text-sm text-muted-foreground">{copy.description}</p>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-3">
|
||||
<CloudArrowDown size={20} className="text-accent" />
|
||||
<div>
|
||||
<Label className="text-base">{copy.label}</Label>
|
||||
<p className="text-xs text-muted-foreground">{copy.status}</p>
|
||||
</div>
|
||||
</div>
|
||||
<Button onClick={onUpdate}>{copy.action}</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
89
src/data/pwa-settings.json
Normal file
89
src/data/pwa-settings.json
Normal file
@@ -0,0 +1,89 @@
|
||||
{
|
||||
"header": {
|
||||
"title": "PWA Settings",
|
||||
"description": "Configure Progressive Web App features and behavior"
|
||||
},
|
||||
"install": {
|
||||
"title": "Installation Status",
|
||||
"description": "Install the app for offline access and better performance",
|
||||
"label": "App Installation",
|
||||
"status": {
|
||||
"installed": "Installed",
|
||||
"available": "Available",
|
||||
"notAvailable": "Not available"
|
||||
},
|
||||
"badge": {
|
||||
"installed": "Installed",
|
||||
"notAvailable": "Not Available"
|
||||
},
|
||||
"action": {
|
||||
"install": "Install Now"
|
||||
}
|
||||
},
|
||||
"connection": {
|
||||
"title": "Connection Status",
|
||||
"description": "Current network connectivity status",
|
||||
"label": "Network Status",
|
||||
"status": {
|
||||
"online": "Connected to internet",
|
||||
"offline": "Working offline"
|
||||
},
|
||||
"badge": {
|
||||
"online": "Online",
|
||||
"offline": "Offline"
|
||||
}
|
||||
},
|
||||
"update": {
|
||||
"title": "Update Available",
|
||||
"description": "A new version of the app is ready to install",
|
||||
"label": "App Update",
|
||||
"status": "Update now for latest features",
|
||||
"action": "Update Now"
|
||||
},
|
||||
"notifications": {
|
||||
"title": "Notifications",
|
||||
"description": "Receive updates about your projects and builds",
|
||||
"label": "Push Notifications",
|
||||
"permissionLabel": "Permission:",
|
||||
"blocked": "Notifications are blocked. Please enable them in your browser settings."
|
||||
},
|
||||
"cache": {
|
||||
"title": "Cache Management",
|
||||
"description": "Manage offline storage and cached resources",
|
||||
"labels": {
|
||||
"size": "Cache Size",
|
||||
"serviceWorker": "Service Worker"
|
||||
},
|
||||
"status": {
|
||||
"active": "Active",
|
||||
"inactive": "Inactive"
|
||||
},
|
||||
"action": {
|
||||
"clear": "Clear Cache & Reload"
|
||||
},
|
||||
"helper": "This will remove all cached files and reload the app",
|
||||
"storageUnit": "MB"
|
||||
},
|
||||
"features": {
|
||||
"title": "PWA Features",
|
||||
"description": "Progressive Web App capabilities",
|
||||
"items": {
|
||||
"offline": "Offline Support",
|
||||
"installable": "Installable",
|
||||
"backgroundSync": "Background Sync",
|
||||
"pushNotifications": "Push Notifications",
|
||||
"shortcuts": "App Shortcuts"
|
||||
}
|
||||
},
|
||||
"toasts": {
|
||||
"installSuccess": "App installed successfully!",
|
||||
"installCancelled": "Installation cancelled",
|
||||
"update": "Updating app...",
|
||||
"cacheCleared": "Cache cleared! Reloading...",
|
||||
"notificationsEnabled": "Notifications enabled",
|
||||
"notificationsDenied": "Notification permission denied"
|
||||
},
|
||||
"defaults": {
|
||||
"cacheCalculating": "Calculating..."
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user