Skip to content

Commit

Permalink
fix refresh. tweak app picker flows
Browse files Browse the repository at this point in the history
  • Loading branch information
a-type committed Mar 27, 2024
1 parent bd032ec commit 8b32587
Show file tree
Hide file tree
Showing 15 changed files with 86 additions and 18 deletions.
4 changes: 3 additions & 1 deletion apps/gnocchi/web/src/components/nav/NavBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ export function NavBar({}: NavBarProps) {
<Suspense>
<div className="hidden sm:(flex flex-row gap-2 items-center justify-center px-2 py-2 mt-3)">
<img src="/android-chrome-192x192.png" className="w-30px h-30px" />
<h1 className="text-sm font-title font-medium">Gnocchi</h1>
<h1 className="text-md [font-family:'VC_Henrietta_Trial','Noto_Serif',serif] font-normal">
Gnocchi
</h1>
</div>
<GroceriesNavBarLink active={matchGroceries} />
<PantryNavBarLink active={matchPurchased} />
Expand Down
5 changes: 5 additions & 0 deletions packages/client/src/components/AppPicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ export function AppPicker({ className, children }: AppPickerProps) {
return () => window.removeEventListener('message', listener);
}, []);

if (getIsPWAInstalled()) {
// app picker doesn't really work in a PWA :(
return null;
}

return (
<Popover>
<PopoverTrigger className={className} asChild>
Expand Down
6 changes: 5 additions & 1 deletion packages/client/src/components/LogoutButton.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Button, ButtonProps } from '@a-type/ui/components/button';
import { CONFIG } from '../index.js';
import { Icon } from '@a-type/ui/components/icon';

export interface LogoutButtonProps extends ButtonProps {
returnTo?: string;
Expand All @@ -12,7 +13,10 @@ export function LogoutButton(props: LogoutButtonProps) {
}
return (
<Button asChild {...props}>
<a href={url.toString()}>Login</a>
<a href={url.toString()}>
Log out
<Icon name="arrowRight" />
</a>
</Button>
);
}
28 changes: 27 additions & 1 deletion packages/client/src/components/UserMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
} from '@a-type/ui/components/dropdownMenu';
import {
CONFIG,
getIsPWAInstalled,
graphql,
useAppId,
useIsLoggedIn,
Expand All @@ -32,6 +33,14 @@ export function UserMenu({
const isLoggedIn = useIsLoggedIn();
const appId = useAppId();

const openPwaHackCatalog = () => {
// since we can't just open a new tab, use a share
// intent to open the PWA catalog URL
navigator.share({
url: `${CONFIG.HOME_ORIGIN}/apps`,
});
};

return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
Expand All @@ -40,6 +49,23 @@ export function UserMenu({
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent>
{getIsPWAInstalled() ? (
<DropdownMenuItem onClick={openPwaHackCatalog}>
More apps
<DropdownMenuItemRightSlot>
<Icon name="new_window" />
</DropdownMenuItemRightSlot>
</DropdownMenuItem>
) : (
<DropdownMenuItem asChild>
<a href={`${CONFIG.HOME_ORIGIN}/apps`} target="_blank">
More apps
<DropdownMenuItemRightSlot>
<Icon name="new_window" />
</DropdownMenuItemRightSlot>
</a>
</DropdownMenuItem>
)}
{!isLoggedIn ? (
<DropdownMenuItem
asChild
Expand Down Expand Up @@ -74,7 +100,7 @@ export function UserMenu({
)}
<DropdownMenuItem asChild>
<a href={`${CONFIG.API_ORIGIN}/logout`}>
Logout
Log out
<DropdownMenuItemRightSlot>
<Icon name="arrowRight" />
</DropdownMenuItemRightSlot>
Expand Down
5 changes: 3 additions & 2 deletions packages/client/src/fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ const refreshTokenStorage = {

export async function refreshSession(apiOrigin: string) {
const refreshToken = refreshTokenStorage.get();
if (!refreshToken) return refreshSessionViaIframe();
if (!refreshToken || refreshToken === 'undefined')
return refreshSessionViaIframe();
try {
const response = await fetch(`${apiOrigin}/auth/refresh`, {
method: 'POST',
Expand Down Expand Up @@ -86,7 +87,7 @@ async function refreshSessionViaIframe() {
window.addEventListener('message', (event) => {
if (event.data.type === 'refresh-session') {
if (event.data.success) {
console.debug('refreshed session via iframe');
console.log('refreshed session via iframe');
// store the new refresh token
refreshTokenStorage.set(event.data.success.refreshToken);
resolve();
Expand Down
19 changes: 17 additions & 2 deletions packages/client/src/graphql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ export type { FragmentOf, ResultOf, VariablesOf } from 'gql.tada';

function createErrorHandler(onError?: (err: string) => void) {
return async function handleError(error: CombinedError) {
console.error(error);
let errorMessage: string | undefined =
'An unexpected error occurred. Please try again.';
if (error.graphQLErrors) {
Expand Down Expand Up @@ -76,7 +75,9 @@ export function createGraphQLClient({
url: `${origin}/graphql`,
exchanges: [
refocus,
errorExchange({ onError: createErrorHandler(onError) }),
errorExchange({
onError: createErrorHandler(deduplicateErrors(onError)),
}),
cacheExchange,
retry,
fetchExchange,
Expand All @@ -89,6 +90,20 @@ export function createGraphQLClient({
});
}

function deduplicateErrors(onError?: (error: string) => void) {
if (!onError) return undefined;
// only show 1 of each error message within a time window
const errors = new Set<string>();
return (error: string) => {
if (errors.has(error)) return;
errors.add(error);
setTimeout(() => {
errors.delete(error);
}, 5000);
onError(error);
};
}

export function createMinimalGraphQLClient({
origin = CONFIG.API_ORIGIN,
onError,
Expand Down
4 changes: 3 additions & 1 deletion packages/client/src/platform.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
const PRETEND_PWA = false;

export async function requestPersistentStorage() {
if (getIsPWAInstalled() && navigator.storage && navigator.storage.persist) {
const result = await navigator.storage.persist();
Expand All @@ -6,7 +8,7 @@ export async function requestPersistentStorage() {
}

export function getIsPWAInstalled() {
return window.matchMedia('(display-mode: standalone)').matches;
return PRETEND_PWA || window.matchMedia('(display-mode: standalone)').matches;
}

export function getOS() {
Expand Down
2 changes: 1 addition & 1 deletion server/src/auth/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ declare module '@a-type/auth' {

export const sessions = new SessionManager({
cookieName: 'bsc-session',
expiration: '24h',
expiration: '2m',
async createSession(userId) {
const user = await db
.selectFrom('User')
Expand Down
6 changes: 3 additions & 3 deletions server/src/graphql/builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
PlanInvitation,
User,
} from '@biscuits/db';
import { VerdantLibraryInfo } from '../verdant/verdant.js';
import { LibraryInfo } from '@verdant-web/server';
import { BiscuitsVerdantProfile } from '@biscuits/libraries';
import { ExtractorData } from '@gnocchi.biscuits/scanning';
import { BiscuitsError } from '@biscuits/error';
Expand All @@ -22,8 +22,8 @@ export const builder = new SchemaBuilder<{
User: User & { __typename: 'User' };
Plan: Plan & { __typename: 'Plan' };
PlanInvitation: PlanInvitation & { __typename: 'PlanInvitation' };
PlanLibraryInfo: VerdantLibraryInfo & { id: string };
PlanLibraryReplica: VerdantLibraryInfo['replicas'][number];
PlanLibraryInfo: LibraryInfo & { id: string };
PlanLibraryReplica: LibraryInfo['replicas'][number];
PlanLibraryReplicaProfile: BiscuitsVerdantProfile;
ClaimPlanInvitationResult: {
userId: string;
Expand Down
6 changes: 5 additions & 1 deletion server/src/graphql/types/plan.ts
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,11 @@ Plan.implement({
return [];
}
} else {
return plan.featureFlags ?? [];
const flags = plan.featureFlags ?? [];
if (!Array.isArray(flags)) {
return [];
}
return flags;
}
},
}),
Expand Down
2 changes: 1 addition & 1 deletion server/src/routers/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ authRouter
const provider = req.params.provider;
return authHandlers.handleOAuthCallbackRequest(req, { provider });
})
.post('/logout', authHandlers.handleLogoutRequest)
.all('/logout', authHandlers.handleLogoutRequest)
.post('/begin-email-signup', authHandlers.handleSendEmailVerificationRequest)
.post('/complete-email-signup', authHandlers.handleVerifyEmailRequest)
.post('/email-login', authHandlers.handleEmailLoginRequest)
Expand Down
3 changes: 0 additions & 3 deletions server/src/verdant/verdant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,3 @@ export const verdantServer = new Server({

verdantServer.on('error', console.error);
verdantServer.on('changes', changeListener.update);

// TODO: expose named types in Verdant for...
export type VerdantLibraryInfo = Awaited<ReturnType<Server['getLibraryInfo']>>;
5 changes: 5 additions & 0 deletions web/src/pages/AppsPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export function AppsPage() {
return <div>Todo: apps</div>;
}

export default AppsPage;
5 changes: 4 additions & 1 deletion web/src/pages/RefreshSessionPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ export function RefreshSessionPage() {
const success = data.data?.me;
useEffect(() => {
if (window.top) {
window.top.postMessage({ type: 'refresh-session', success }, '*');
window.top.postMessage(
JSON.stringify({ type: 'refresh-session', success }),
'*',
);
}
}, [success]);
return null;
Expand Down
4 changes: 4 additions & 0 deletions web/src/pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ const routes = makeRoutes([
path: '/refresh-session',
component: RefreshSessionPage,
},
{
path: '/apps',
component: lazy(() => import('./AppsPage.jsx')),
},
]);

export function Pages() {
Expand Down

0 comments on commit 8b32587

Please sign in to comment.