Skip to content

Commit ee048b9

Browse files
committed
chore(demo): split user auth from app section
1 parent da0fcb3 commit ee048b9

File tree

9 files changed

+154
-95
lines changed

9 files changed

+154
-95
lines changed

examples/build.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ Asset requirements:
122122
`https://raw.githubusercontent.com/OneSignal/sdk-shared/refs/heads/main/assets/onesignal_logo.svg`
123123
- Save to demo assets (for example `src/assets/onesignal_logo.svg`) and render it in the header component used by this demo (`src/pages/Home.tsx`) via import:
124124
`import OneSignalLogo from '../assets/onesignal_logo.svg';`
125-
- Use the logo as the `OneSignal` wordmark and show separate `Sample App` text
125+
- Use the logo as the `OneSignal` wordmark and show separate `Cordova` text
126126
- Do not inline long SVG paths in `Home.tsx`/header JSX
127127
128128
- Download padded icon PNG:
@@ -442,7 +442,7 @@ User Section layout (separate section card titled "User", placed after App Secti
442442
2. `LOGIN USER` button:
443443
- Shows `LOGIN USER` when no user is logged in
444444
- Shows `SWITCH USER` when a user is logged in
445-
- Opens modal with empty `External User Id` field
445+
- Opens "Login User" modal with empty `External User Id` field
446446
447447
3. `LOGOUT USER` button (only visible when a user is logged in)
448448
@@ -507,8 +507,8 @@ Send In-App Message Section:
507507
Aliases Section:
508508
509509
- Section title includes info icon (use `MdInfoOutline` from `react-icons/md`).
510-
- List showing key-value pairs (read-only, no delete icons).
511-
- Each item shows: Label | ID.
510+
- Stacked key-value list (read-only, no delete icons).
511+
- Each item shows Label on top, ID below (see styles.md "Stacked" list layout).
512512
- Hide special alias keys from display:
513513
- `external_id`
514514
- `onesignal_id`

examples/demo/src/App.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
import { IonApp, IonRouterOutlet, setupIonicReact } from '@ionic/react';
22
import { IonReactRouter } from '@ionic/react-router';
33
import { Redirect, Route } from 'react-router-dom';
4+
import { StatusBar, Style } from '@capacitor/status-bar';
45
import { AppContextProvider } from './context/AppContext';
56
import Home from './pages/Home';
67
import Secondary from './pages/Secondary';
78

9+
StatusBar.setStyle({ style: Style.Dark }).catch(() => {});
10+
811
/* Core CSS required for Ionic components to work properly */
912
import '@ionic/react/css/core.css';
1013

examples/demo/src/components/ListWidgets.tsx

Lines changed: 40 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
import type { FC } from 'react';
1+
import { type FC, useState } from 'react';
22
import { MdClose } from 'react-icons/md';
33

4+
const COLLAPSE_THRESHOLD = 5;
5+
46
export type PairItem = {
57
key: string;
68
value: string;
@@ -36,7 +38,7 @@ export const PairList: FC<PairListProps> = ({
3638
items.map((item) => (
3739
<div key={item.key} className="list-item two-line">
3840
<div>
39-
<strong>{item.key}</strong>
41+
<span className="list-key">{item.key}</span>
4042
<span>{item.value}</span>
4143
</div>
4244
{onRemove ? (
@@ -60,25 +62,43 @@ export const SingleList: FC<SingleListProps> = ({
6062
items,
6163
emptyText,
6264
onRemove,
63-
}) => (
64-
<div className="card list-card">
65-
{items.length ? (
66-
items.map((item) => (
67-
<div key={item} className="list-item">
68-
<span>{item}</span>
69-
{onRemove ? (
65+
}) => {
66+
const [expanded, setExpanded] = useState(false);
67+
const showAll = expanded || items.length <= COLLAPSE_THRESHOLD;
68+
const displayItems = showAll ? items : items.slice(0, COLLAPSE_THRESHOLD);
69+
const hiddenCount = items.length - COLLAPSE_THRESHOLD;
70+
71+
return (
72+
<div className="card list-card">
73+
{items.length ? (
74+
<>
75+
{displayItems.map((item) => (
76+
<div key={item} className="list-item">
77+
<span>{item}</span>
78+
{onRemove ? (
79+
<button
80+
type="button"
81+
className="delete-btn"
82+
onClick={() => onRemove(item)}
83+
>
84+
<MdClose />
85+
</button>
86+
) : null}
87+
</div>
88+
))}
89+
{!showAll && hiddenCount > 0 && (
7090
<button
7191
type="button"
72-
className="delete-btn"
73-
onClick={() => onRemove(item)}
92+
className="more-link"
93+
onClick={() => setExpanded(true)}
7494
>
75-
<MdClose />
95+
{hiddenCount} more
7696
</button>
77-
) : null}
78-
</div>
79-
))
80-
) : (
81-
<EmptyState text={emptyText} />
82-
)}
83-
</div>
84-
);
97+
)}
98+
</>
99+
) : (
100+
<EmptyState text={emptyText} />
101+
)}
102+
</div>
103+
);
104+
};

examples/demo/src/components/modals/CustomNotificationModal.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { useEffect, useState } from 'react';
21
import type { FC } from 'react';
2+
import { useEffect, useState } from 'react';
33
import ModalShell from './ModalShell';
44

55
interface CustomNotificationModalProps {
@@ -41,7 +41,7 @@ const CustomNotificationModal: FC<CustomNotificationModalProps> = ({
4141
onChange={(event) => setTitle(event.target.value)}
4242
placeholder="Title"
4343
/>
44-
<textarea
44+
<input
4545
value={body}
4646
onChange={(event) => setBody(event.target.value)}
4747
placeholder="Body"
@@ -50,7 +50,9 @@ const CustomNotificationModal: FC<CustomNotificationModalProps> = ({
5050
<button type="button" onClick={onClose}>
5151
Cancel
5252
</button>
53-
<button type="submit">Send</button>
53+
<button type="submit" disabled={!title.trim() || !body.trim()}>
54+
Send
55+
</button>
5456
</div>
5557
</form>
5658
</ModalShell>

examples/demo/src/components/modals/OutcomeModal.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ const OutcomeModal: FC<OutcomeModalProps> = ({ open, onClose, onSubmit }) => {
2727
<ModalShell open={open}>
2828
<form
2929
autoCapitalize="off"
30-
className="outcome-modal"
3130
onSubmit={(event) => {
3231
event.preventDefault();
3332
const trimmed = name.trim();

examples/demo/src/components/sections/AppSection.tsx

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,21 @@
11
import { IonToggle } from '@ionic/react';
22
import type { FC } from 'react';
3-
import ActionButton from '../ActionButton';
43

54
interface AppSectionProps {
65
appId: string;
76
consentRequired: boolean;
87
privacyConsentGiven: boolean;
9-
externalUserId: string | undefined;
108
onToggleConsent: (checked: boolean) => void;
119
onTogglePrivacyConsent: (checked: boolean) => void;
12-
onLogin: () => void;
13-
onLogout: () => void;
1410
}
1511

1612
const AppSection: FC<AppSectionProps> = ({
1713
appId,
1814
consentRequired,
1915
privacyConsentGiven,
20-
externalUserId,
2116
onToggleConsent,
2217
onTogglePrivacyConsent,
23-
onLogin,
24-
onLogout,
2518
}) => {
26-
const isLoggedIn = Boolean(externalUserId);
27-
2819
return (
2920
<section className="section">
3021
<h2>APP</h2>
@@ -69,27 +60,6 @@ const AppSection: FC<AppSectionProps> = ({
6960
</>
7061
) : null}
7162
</div>
72-
<div className="card kv-card">
73-
<div className="kv-row">
74-
<span>Status</span>
75-
<span className={isLoggedIn ? 'text-success' : undefined}>
76-
{isLoggedIn ? 'Logged In' : 'Anonymous'}
77-
</span>
78-
</div>
79-
<div className="divider" />
80-
<div className="kv-row">
81-
<span>External ID</span>
82-
<span className="id-value">{externalUserId ?? '–'}</span>
83-
</div>
84-
</div>
85-
<ActionButton type="button" onClick={onLogin}>
86-
{isLoggedIn ? 'SWITCH USER' : 'LOGIN USER'}
87-
</ActionButton>
88-
{isLoggedIn ? (
89-
<ActionButton variant="outline" type="button" onClick={onLogout}>
90-
LOGOUT USER
91-
</ActionButton>
92-
) : null}
9363
</section>
9464
);
9565
};
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import type { FC } from 'react';
2+
import ActionButton from '../ActionButton';
3+
4+
interface UserSectionProps {
5+
externalUserId: string | undefined;
6+
onLogin: () => void;
7+
onLogout: () => void;
8+
}
9+
10+
const UserSection: FC<UserSectionProps> = ({
11+
externalUserId,
12+
onLogin,
13+
onLogout,
14+
}) => {
15+
const isLoggedIn = Boolean(externalUserId);
16+
17+
return (
18+
<section className="section">
19+
<h2>USER</h2>
20+
<div className="card kv-card">
21+
<div className="kv-row">
22+
<span>Status</span>
23+
<span className={isLoggedIn ? 'text-success' : undefined}>
24+
{isLoggedIn ? 'Logged In' : 'Anonymous'}
25+
</span>
26+
</div>
27+
<div className="divider" />
28+
<div className="kv-row">
29+
<span>External ID</span>
30+
<span className="id-value">{externalUserId ?? '–'}</span>
31+
</div>
32+
</div>
33+
<ActionButton type="button" onClick={onLogin}>
34+
{isLoggedIn ? 'SWITCH USER' : 'LOGIN USER'}
35+
</ActionButton>
36+
{isLoggedIn ? (
37+
<ActionButton variant="outline" type="button" onClick={onLogout}>
38+
LOGOUT USER
39+
</ActionButton>
40+
) : null}
41+
</section>
42+
);
43+
};
44+
45+
export default UserSection;

0 commit comments

Comments
 (0)