Skip to content

Commit

Permalink
feat: basic notifications (#9)
Browse files Browse the repository at this point in the history
  • Loading branch information
ImLunaHey authored Dec 20, 2024
1 parent 49d1fd3 commit b714e8c
Show file tree
Hide file tree
Showing 5 changed files with 173 additions and 1 deletion.
8 changes: 7 additions & 1 deletion src/components/Navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ import { useAuth } from '../lib/bluesky/hooks/useAuth';
import { Link } from './ui/Link';
import { useBlueskyStore } from '../lib/bluesky/store';

const NotificationsLink = () => {
const { t } = useTranslation('notifications');
return <Link to="/notifications">{t('notifications')}</Link>;
};

const ProfileLink = () => {
const { session } = useBlueskyStore();
const { t } = useTranslation('profile');
Expand Down Expand Up @@ -48,7 +53,8 @@ export const Navbar = () => {
<h1 className="text-2xl font-bold">{t('appName')}</h1>
</Link>
<div className="flex flex-row gap-2">
<ProfileLink />
{isAuthenticated && <NotificationsLink />}
{isAuthenticated && <ProfileLink />}
<SettingsLink />
{isAuthenticated ? <LogoutButton /> : <LoginButton />}
</div>
Expand Down
11 changes: 11 additions & 0 deletions src/i18n/lang/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,15 @@ export const en = {
debug: {
notImplemented: 'NOT IMPLEMENTED: {{value}}',
},
notifications: {
notifications: 'notifications',
noNotifications: 'no notifications',
followedYou: 'followed you',
likedYourPost: 'liked your post',
repostedYourPost: 'reposted your post',
repliedToYourPost: 'replied to your post',
mentionedYou: 'mentioned you',
quotedYourPost: 'quoted your post',
joinedYourStarterpack: 'joined your starterpack',
},
} as const;
17 changes: 17 additions & 0 deletions src/lib/bluesky/hooks/useNotifications.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { useQuery } from '@tanstack/react-query';
import { useBlueskyStore } from '../store';

export function useNotifications() {
const { agent } = useBlueskyStore();

return useQuery({
queryKey: ['notifications'],
queryFn: async () => {
if (!agent) throw new Error('Not authenticated');

const response = await agent.api.app.bsky.notification.listNotifications();
return response.data.notifications;
},
enabled: !!agent,
});
}
26 changes: 26 additions & 0 deletions src/routeTree.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { createFileRoute } from '@tanstack/react-router'
// Import Routes

import { Route as rootRoute } from './routes/__root'
import { Route as NotificationsImport } from './routes/notifications'
import { Route as ProfileHandleRouteImport } from './routes/profile/$handle/route'
import { Route as ProfileHandleIndexImport } from './routes/profile/$handle/index'
import { Route as ProfileHandlePostPostIdImport } from './routes/profile/$handle/post.$postId'
Expand All @@ -38,6 +39,12 @@ const LoginLazyRoute = LoginLazyImport.update({
getParentRoute: () => rootRoute,
} as any).lazy(() => import('./routes/login.lazy').then((d) => d.Route))

const NotificationsRoute = NotificationsImport.update({
id: '/notifications',
path: '/notifications',
getParentRoute: () => rootRoute,
} as any)

const IndexLazyRoute = IndexLazyImport.update({
id: '/',
path: '/',
Expand Down Expand Up @@ -79,6 +86,13 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof IndexLazyImport
parentRoute: typeof rootRoute
}
'/notifications': {
id: '/notifications'
path: '/notifications'
fullPath: '/notifications'
preLoaderRoute: typeof NotificationsImport
parentRoute: typeof rootRoute
}
'/login': {
id: '/login'
path: '/login'
Expand Down Expand Up @@ -141,6 +155,7 @@ const ProfileHandleRouteRouteWithChildren =

export interface FileRoutesByFullPath {
'/': typeof IndexLazyRoute
'/notifications': typeof NotificationsRoute
'/login': typeof LoginLazyRoute
'/settings': typeof SettingsLazyRoute
'/profile/$handle': typeof ProfileHandleRouteRouteWithChildren
Expand All @@ -151,6 +166,7 @@ export interface FileRoutesByFullPath {

export interface FileRoutesByTo {
'/': typeof IndexLazyRoute
'/notifications': typeof NotificationsRoute
'/login': typeof LoginLazyRoute
'/settings': typeof SettingsLazyRoute
'/tag/$tag': typeof TagTagLazyRoute
Expand All @@ -161,6 +177,7 @@ export interface FileRoutesByTo {
export interface FileRoutesById {
__root__: typeof rootRoute
'/': typeof IndexLazyRoute
'/notifications': typeof NotificationsRoute
'/login': typeof LoginLazyRoute
'/settings': typeof SettingsLazyRoute
'/profile/$handle': typeof ProfileHandleRouteRouteWithChildren
Expand All @@ -173,6 +190,7 @@ export interface FileRouteTypes {
fileRoutesByFullPath: FileRoutesByFullPath
fullPaths:
| '/'
| '/notifications'
| '/login'
| '/settings'
| '/profile/$handle'
Expand All @@ -182,6 +200,7 @@ export interface FileRouteTypes {
fileRoutesByTo: FileRoutesByTo
to:
| '/'
| '/notifications'
| '/login'
| '/settings'
| '/tag/$tag'
Expand All @@ -190,6 +209,7 @@ export interface FileRouteTypes {
id:
| '__root__'
| '/'
| '/notifications'
| '/login'
| '/settings'
| '/profile/$handle'
Expand All @@ -201,6 +221,7 @@ export interface FileRouteTypes {

export interface RootRouteChildren {
IndexLazyRoute: typeof IndexLazyRoute
NotificationsRoute: typeof NotificationsRoute
LoginLazyRoute: typeof LoginLazyRoute
SettingsLazyRoute: typeof SettingsLazyRoute
ProfileHandleRouteRoute: typeof ProfileHandleRouteRouteWithChildren
Expand All @@ -209,6 +230,7 @@ export interface RootRouteChildren {

const rootRouteChildren: RootRouteChildren = {
IndexLazyRoute: IndexLazyRoute,
NotificationsRoute: NotificationsRoute,
LoginLazyRoute: LoginLazyRoute,
SettingsLazyRoute: SettingsLazyRoute,
ProfileHandleRouteRoute: ProfileHandleRouteRouteWithChildren,
Expand All @@ -226,6 +248,7 @@ export const routeTree = rootRoute
"filePath": "__root.tsx",
"children": [
"/",
"/notifications",
"/login",
"/settings",
"/profile/$handle",
Expand All @@ -235,6 +258,9 @@ export const routeTree = rootRoute
"/": {
"filePath": "index.lazy.tsx"
},
"/notifications": {
"filePath": "notifications.tsx"
},
"/login": {
"filePath": "login.lazy.tsx"
},
Expand Down
112 changes: 112 additions & 0 deletions src/routes/notifications.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import { createFileRoute } from '@tanstack/react-router';
import { useTranslation } from 'react-i18next';
import { useNotifications } from '../lib/bluesky/hooks/useNotifications';
import { Debug } from '../components/ui/Debug';
import { Notification as BskyNotification } from '@atproto/api/dist/client/types/app/bsky/notification/listNotifications';

export const Route = createFileRoute('/notifications')({
component: RouteComponent,
});

function RouteComponent() {
const { t } = useTranslation(['app', 'notifications']);
const { data: notifications, isLoading } = useNotifications();

if (isLoading) return <div>{t('loading')}</div>;

return (
<div>
{t('notifications:notifications')}
{notifications?.map((notification) => <Notification key={notification.uri} notification={notification} />)}
</div>
);
}

function Notification({ notification }: { notification: BskyNotification }) {
switch (notification.reason) {
case 'follow':
return <FollowNotification notification={notification} />;
case 'like':
return <LikeNotification notification={notification} />;
case 'repost':
return <RepostNotification notification={notification} />;
case 'reply':
return <ReplyNotification notification={notification} />;
case 'mention':
return <MentionNotification notification={notification} />;
case 'quote':
return <QuoteNotification notification={notification} />;
case 'starterpack-joined':
return <StarterpackJoinedNotification notification={notification} />;
}

return (
<div>
{notification.author.displayName}
<Debug value={notification} />
</div>
);
}

function FollowNotification({ notification }: { notification: BskyNotification }) {
const { t } = useTranslation('notifications');
return (
<div>
{notification.author.displayName} {t('followedYou')}
</div>
);
}

function LikeNotification({ notification }: { notification: BskyNotification }) {
const { t } = useTranslation('notifications');
return (
<div>
{notification.author.displayName} {t('likedYourPost')}
</div>
);
}

function RepostNotification({ notification }: { notification: BskyNotification }) {
const { t } = useTranslation('notifications');
return (
<div>
{notification.author.displayName} {t('repostedYourPost')}
</div>
);
}

function ReplyNotification({ notification }: { notification: BskyNotification }) {
const { t } = useTranslation('notifications');
return (
<div>
{notification.author.displayName} {t('repliedToYourPost')}
</div>
);
}

function MentionNotification({ notification }: { notification: BskyNotification }) {
const { t } = useTranslation('notifications');
return (
<div>
{notification.author.displayName} {t('mentionedYou')}
</div>
);
}

function QuoteNotification({ notification }: { notification: BskyNotification }) {
const { t } = useTranslation('notifications');
return (
<div>
{notification.author.displayName} {t('quotedYourPost')}
</div>
);
}

function StarterpackJoinedNotification({ notification }: { notification: BskyNotification }) {
const { t } = useTranslation('notifications');
return (
<div>
{notification.author.displayName} {t('joinedYourStarterpack')}
</div>
);
}

0 comments on commit b714e8c

Please sign in to comment.