Skip to content
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

feat: install pwa #9

Merged
merged 3 commits into from
Jul 15, 2024
Merged
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
2 changes: 1 addition & 1 deletion public/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"sizes": "512x512"
}
],
"start_url": ".",
"start_url": "/",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,33 +6,28 @@ import { NightModeSettings } from '../nightModeSettings/NightModeSettings';
import { ThemePicker } from '../ThemePicker/ThemePicker';
import { BaseButton } from '@app/components/common/BaseButton/BaseButton';
import { useAppSelector } from '@app/hooks/reduxHooks';
import { useAppDispatch } from '@app/hooks/reduxHooks';
import { setShowAlert } from '@app/store/slices/pwaSlice';
import * as S from './SettingsOverlay.styles';
import { Alert } from 'antd';

export const SettingsOverlay: React.FC = ({ ...props }) => {
const { t } = useTranslation();
const { isPWASupported } = useAppSelector((state) => state.pwa);
const [promptEvent, setPromptEvent] = useState<Event | null>(null);

useEffect(() => {
const handler = (e: Event) => {
e.preventDefault();
console.log('beforeinstallprompt event fired');
setPromptEvent(e as any);
};

window.addEventListener('beforeinstallprompt', handler as EventListener);

return () => {
window.removeEventListener('beforeinstallprompt', handler as EventListener);
};
}, []);

useEffect(() => {
if (promptEvent) {
console.log('Prompt event set:', promptEvent);

const dispatch = useAppDispatch();
const { isPWASupported, event } = useAppSelector((state) => state.pwa);

const handleInstallClick = () => {
console.log('event', event);
if (event == null) {
// Display an alert if event is not available
console.log('Event is not available');
dispatch(setShowAlert(true));
return;
}
}, [promptEvent]);

(event as BeforeInstallPromptEvent).prompt();
};
return (
<S.SettingsOverlayMenu {...props}>
<DropdownCollapse bordered={false} expandIconPosition="end" ghost defaultActiveKey="themePicker">
Expand All @@ -46,9 +41,9 @@ export const SettingsOverlay: React.FC = ({ ...props }) => {
<S.Text>
<Link to="/logout">{t('header.logout')}</Link>
</S.Text>
{isPWASupported && promptEvent && (
{isPWASupported && (
<S.PwaInstallWrapper>
<BaseButton block type="primary" onClick={() => (promptEvent as any).prompt()}>
<BaseButton block type="primary" onClick={handleInstallClick}>
{t('common.pwa')}
</BaseButton>
</S.PwaInstallWrapper>
Expand Down
35 changes: 35 additions & 0 deletions src/components/layouts/main/MainLayout/MainLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import MainSider from '../sider/MainSider/MainSider';
import MainContent from '../MainContent/MainContent';
import { MainHeader } from '../MainHeader/MainHeader';
import * as S from './MainLayout.styles';
import { setShowAlert } from '@app/store/slices/pwaSlice';

import { Outlet, useLocation, useNavigate } from 'react-router-dom';
import {
MEDICAL_DASHBOARD_PATH,
Expand All @@ -16,15 +18,21 @@ import { References } from '@app/components/common/References/References';
import { useAppDispatch } from '@app/hooks/reduxHooks';
import { doLogout } from '@app/store/slices/authSlice';
import useIdleTimer from '@app/hooks/useIdleTimer';
import { Alert, theme } from 'antd';
import { useAppSelector } from '@app/hooks/reduxHooks';
import { themeObject } from '@app/styles/themes/themeVariables';

const MainLayout: React.FC = () => {
const [isTwoColumnsLayout, setIsTwoColumnsLayout] = useState(true);
const [siderCollapsed, setSiderCollapsed] = useState(true);

const { isDesktop } = useResponsive();
const location = useLocation();
const dispatch = useAppDispatch();
const navigate = useNavigate();

const { showAlert } = useAppSelector((state) => state.pwa);
const theme = useAppSelector((state) => state.theme.theme);
const toggleSider = () => setSiderCollapsed(!siderCollapsed);

useEffect(() => {
Expand Down Expand Up @@ -61,6 +69,33 @@ const MainLayout: React.FC = () => {
</div>
{!isTwoColumnsLayout && <References />}
</MainContent>
{showAlert && (
<div
style={{
margin: '1rem',
display: 'flex',
flexDirection: 'row',
width: isDesktop ? '55%' : '90%',
justifyContent: 'center',
position: 'absolute',
bottom: '0',
}}
>
<Alert
message={'There was an error installing the app. Please verify that the app is not already installed.'}
type="warning"
showIcon
closable
onClose={() => dispatch(setShowAlert(false))}
style={{
color: 'black',
width: 'fit-content',

backgroundColor: themeObject[theme].notificationWarning,
}}
/>
</div>
)}
</S.LayoutMain>
</S.LayoutMaster>
);
Expand Down
24 changes: 5 additions & 19 deletions src/hooks/usePWA.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,18 @@
import { useEffect } from 'react';
import { useDispatch } from 'react-redux';
import { setPWASupported } from '@app/store/slices/pwaSlice';
import { addDeferredPrompt } from '@app/store/slices/pwaSlice';

export const usePWA = () => {
export const usePWA = (): void => {
const dispatch = useDispatch();

useEffect(() => {
const handler = (e: Event) => {
const handler = (e: any) => {
e.preventDefault();
// Assuming e is the BeforeInstallPromptEvent
// Instead of storing the event, we just indicate support is available
dispatch(setPWASupported(true));
console.log(e);
dispatch(addDeferredPrompt(e));
};

window.addEventListener('beforeinstallprompt', handler);

console.log('Setting up global beforeinstallprompt listener');
window.addEventListener('beforeinstallprompt', (e) => {
e.preventDefault();
console.log('Global beforeinstallprompt event fired and stored');
(window as any).deferredPrompt = e;
});

return () => {
window.removeEventListener('beforeinstallprompt', handler);
// Optionally, dispatch that PWA is no longer supported if the event is dismissed
dispatch(setPWASupported(false));
};
}, [dispatch]);
};

Expand Down
11 changes: 10 additions & 1 deletion src/store/slices/pwaSlice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ import { PayloadAction, createSlice } from '@reduxjs/toolkit';

// Define the initial state using only serializable values
const initialState = {
event: null as BeforeInstallPromptEvent | null,
isPWASupported: false,
showAlert: false,
isStandalone: window.matchMedia('(display-mode: standalone)').matches,
};

Expand All @@ -18,11 +20,18 @@ export const pwaSlice = createSlice({
clearPWASupport: (state) => {
state.isPWASupported = false;
},
addDeferredPrompt: (state, action: PayloadAction<BeforeInstallPromptEvent>) => {
state.event = action.payload;
state.isPWASupported = true;
},
setShowAlert: (state, action: PayloadAction<boolean>) => {
state.showAlert = action.payload;
},
},
});

// Exporting actions
export const { setPWASupported, clearPWASupport } = pwaSlice.actions;
export const { setPWASupported, clearPWASupport, addDeferredPrompt, setShowAlert } = pwaSlice.actions;

export default pwaSlice.reducer;

Expand Down
5 changes: 4 additions & 1 deletion src/store/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ const initialState = {

export const store = configureStore({
reducer: rootReducer,
middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(errorLoggingMiddleware),
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
serializableCheck: false,
}).concat(errorLoggingMiddleware),
preloadedState: initialState,
});

Expand Down
4 changes: 3 additions & 1 deletion src/styles/GlobalStyle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ export default createGlobalStyle`
.ant-picker-cell {
color: var(--text-main-color);
}

.ant-picker-cell-in-view .ant-picker-calendar-date-value {
color: var(--text-main-color);
font-weight: ${FONT_WEIGHT.bold};
Expand Down Expand Up @@ -205,6 +204,9 @@ export default createGlobalStyle`
background-color: white;
border-color: themeObject[theme].textMain;
}
.ant-alert-message{
color: black
}

.custom-checkbox-group .ant-checkbox-checked .ant-checkbox-inner {
background-color: #1890ff;
Expand Down
Loading