mirror of
https://github.com/block/buzz.git
synced 2026-10-27 04:30:52 +00:00
feat(desktop): improve new user defaults for presence and notifications (#376)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -170,10 +170,21 @@ export function useNotificationSettings(pubkey?: string) {
|
||||
const [errorMessage, setErrorMessage] = React.useState<string | null>(null);
|
||||
const [isUpdatingDesktopEnabled, setIsUpdatingDesktopEnabled] =
|
||||
React.useState(false);
|
||||
const isNewUserRef = React.useRef(
|
||||
normalizedPubkey.length > 0 &&
|
||||
window.localStorage.getItem(
|
||||
notificationSettingsStorageKey(normalizedPubkey),
|
||||
) === null,
|
||||
);
|
||||
|
||||
React.useEffect(() => {
|
||||
setSettings(readStoredNotificationSettings(normalizedPubkey));
|
||||
setErrorMessage(null);
|
||||
isNewUserRef.current =
|
||||
normalizedPubkey.length > 0 &&
|
||||
window.localStorage.getItem(
|
||||
notificationSettingsStorageKey(normalizedPubkey),
|
||||
) === null;
|
||||
}, [normalizedPubkey]);
|
||||
|
||||
React.useEffect(() => {
|
||||
@@ -191,6 +202,33 @@ export function useNotificationSettings(pubkey?: string) {
|
||||
void refreshPermission();
|
||||
}, [normalizedPubkey]);
|
||||
|
||||
// Auto-request desktop notification permission for new users
|
||||
React.useEffect(() => {
|
||||
if (!normalizedPubkey || !isNewUserRef.current) return;
|
||||
isNewUserRef.current = false;
|
||||
|
||||
let cancelled = false;
|
||||
|
||||
void (async () => {
|
||||
try {
|
||||
const currentPermission = await getDesktopNotificationPermissionState();
|
||||
if (cancelled || currentPermission !== "default") return;
|
||||
const result = await requestDesktopNotificationAccess();
|
||||
if (cancelled) return;
|
||||
setPermission(result);
|
||||
if (result === "granted") {
|
||||
setSettings((current) => ({ ...current, desktopEnabled: true }));
|
||||
}
|
||||
} catch {
|
||||
// Best-effort auto-request; silently ignore errors
|
||||
}
|
||||
})();
|
||||
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, [normalizedPubkey]);
|
||||
|
||||
const setDesktopEnabled = React.useCallback(async (enabled: boolean) => {
|
||||
if (!enabled) {
|
||||
setErrorMessage(null);
|
||||
|
||||
@@ -232,10 +232,6 @@ export function usePresenceSession(pubkey?: string) {
|
||||
),
|
||||
[isDocumentHidden, lastActivityAt, statusClock],
|
||||
);
|
||||
const relayStatus =
|
||||
normalizedPubkey.length > 0
|
||||
? (presenceQuery.data?.[normalizedPubkey] ?? "offline")
|
||||
: "offline";
|
||||
const currentStatus =
|
||||
normalizedPubkey.length === 0
|
||||
? "offline"
|
||||
@@ -245,7 +241,7 @@ export function usePresenceSession(pubkey?: string) {
|
||||
? "away"
|
||||
: presencePreference === "auto"
|
||||
? automaticStatus
|
||||
: relayStatus;
|
||||
: automaticStatus;
|
||||
|
||||
const updatePresence = React.useCallback(
|
||||
async (status: PresenceStatus) => {
|
||||
@@ -283,7 +279,7 @@ export function usePresenceSession(pubkey?: string) {
|
||||
});
|
||||
|
||||
React.useEffect(() => {
|
||||
if (normalizedPubkey.length === 0 || presencePreference === null) {
|
||||
if (normalizedPubkey.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -293,14 +289,10 @@ export function usePresenceSession(pubkey?: string) {
|
||||
}
|
||||
|
||||
syncPresence(currentStatus);
|
||||
}, [currentStatus, normalizedPubkey, presencePreference]);
|
||||
}, [currentStatus, normalizedPubkey]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (
|
||||
normalizedPubkey.length === 0 ||
|
||||
presencePreference === null ||
|
||||
currentStatus === "offline"
|
||||
) {
|
||||
if (normalizedPubkey.length === 0 || currentStatus === "offline") {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -311,7 +303,7 @@ export function usePresenceSession(pubkey?: string) {
|
||||
return () => {
|
||||
window.clearInterval(intervalId);
|
||||
};
|
||||
}, [currentStatus, normalizedPubkey, presencePreference]);
|
||||
}, [currentStatus, normalizedPubkey]);
|
||||
|
||||
return {
|
||||
currentStatus,
|
||||
|
||||
@@ -197,7 +197,7 @@ test("shows presence in sidebar, DM header, and member list", async ({
|
||||
await expect(page.getByTestId("sidebar-profile-card")).toBeVisible();
|
||||
await expect(page.getByTestId("self-presence-badge")).toHaveAttribute(
|
||||
"aria-label",
|
||||
"Offline",
|
||||
"Online",
|
||||
);
|
||||
await expect(page.getByTestId("channel-presence-alice-tyler")).toBeVisible();
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ test("updates presence from the profile menu", async ({ page }) => {
|
||||
await openProfileMenu(page);
|
||||
await expect(
|
||||
page.getByTestId("profile-popover-current-status"),
|
||||
).toContainText("Offline");
|
||||
).toContainText("Online");
|
||||
|
||||
await page.getByTestId("profile-popover-status-away").click();
|
||||
await openProfileMenu(page);
|
||||
|
||||
6
justfile
6
justfile
@@ -203,15 +203,15 @@ mobile_dir := "mobile"
|
||||
|
||||
# Install mobile Flutter dependencies
|
||||
mobile-install:
|
||||
cd {{mobile_dir}} && flutter pub get
|
||||
unset GIT_DIR GIT_WORK_TREE; cd {{mobile_dir}} && flutter pub get
|
||||
|
||||
# Run mobile lint and format checks
|
||||
mobile-check:
|
||||
cd {{mobile_dir}} && dart format --output=none --set-exit-if-changed . && flutter analyze
|
||||
unset GIT_DIR GIT_WORK_TREE; cd {{mobile_dir}} && dart format --output=none --set-exit-if-changed . && flutter analyze
|
||||
|
||||
# Run mobile tests
|
||||
mobile-test:
|
||||
cd {{mobile_dir}} && flutter test
|
||||
unset GIT_DIR GIT_WORK_TREE; cd {{mobile_dir}} && flutter test
|
||||
|
||||
# ─── Database ─────────────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
Reference in New Issue
Block a user