Skip to content

Commit

Permalink
feat(web-ui): post and reaction notification links (#317)
Browse files Browse the repository at this point in the history
  • Loading branch information
johnmasking authored Aug 20, 2024
1 parent d1e6408 commit 7800974
Show file tree
Hide file tree
Showing 22 changed files with 228 additions and 58 deletions.
12 changes: 0 additions & 12 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src/domain/reaction/aggregate/feature.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export default async function feature(requester: Requester, data: DataModel): Pr
createdAt: data.createdAt,
ratingCount: data.ratingCount,
creator: relationData,
postId: data.postId,
hasRated,
comic: comicData,
comment: commentData,
Expand Down
2 changes: 1 addition & 1 deletion src/domain/reaction/aggregate/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type { AggregatedData as RelationData } from '^/domain/relation/aggregate

import type { DataModel } from '../types';

type AggregatedData = Pick<DataModel, 'id' | 'createdAt' | 'ratingCount'> &
type AggregatedData = Pick<DataModel, 'id' | 'createdAt' | 'ratingCount' | 'postId'> &
{
readonly creator: RelationData;
readonly hasRated: boolean;
Expand Down
2 changes: 1 addition & 1 deletion src/domain/reaction/create/feature.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export default async function feature(creatorId: string, postId: string, comicId

const post = await retrievePost(postId);

await createNotification(Types.ADDED_REACTION, creatorId, post.creatorId, postId);
await createNotification(Types.ADDED_REACTION, creatorId, post.creatorId, postId, id);

return id;
}
Expand Down
2 changes: 2 additions & 0 deletions src/webui/Routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import NotFound from './features/NotFound';
import Notifications from './features/Notifications';
import PostDetails from './features/PostDetails';
import Profile from './features/Profile';
import ReactionDetails from './features/ReactionDetails';
import Timeline from './features/Timeline';

export default function Component()
Expand All @@ -38,6 +39,7 @@ export default function Component()
<Route path="/profile/:nickname/:tab?" element={protect(<Profile />)} />
<Route path="/edit/profile" element={protect(<EditProfile />)} />
<Route path="/post/:postId" element={protect(<PostDetails />)} />
<Route path="/post/:postId/reaction/:reactionId" element={protect(<ReactionDetails />)} />
<Route path="/logout" element={protect(<Logout />)} />

<Route path="*" element={<NotFound />} />
Expand Down
2 changes: 2 additions & 0 deletions src/webui/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ export { default as NotificationPanelList } from './notification/PanelList';
export { default as PostDetailsPanel } from './post/DetailsPanel';
export { default as PostPanelGrid } from './post/PanelGrid';
export { default as PostPanelList } from './post/PanelList';
export { default as ReactionLargePanel } from './reaction/LargePanel';
export { default as ReactionPanelList } from './reaction/PanelList';
export { default as SingleReactionRow } from './reaction/SingleReactionRow';
export { default as RelationPanelList } from './relation/PanelList';
export { default as RelationProfile } from './relation/Profile';

15 changes: 8 additions & 7 deletions src/webui/components/notification/Panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,22 @@ type Props = {
readonly notification: NotificationView;
readonly onFollowClick: (relation: RelationView) => Promise<void>;
readonly onCreatorClick: (relation: RelationView) => void;
readonly onComicClick: (post: PostView) => void;
readonly onReactionClick: (reaction: ReactionView) => void;
readonly onPostClick: (post: PostView) => void;
};

function getContent(notification: NotificationView, onComicClick: (post: PostView) => void)
function getContent(notification: NotificationView, onReactionClick: (reaction: ReactionView) => void, onPostClick: (post: PostView) => void)
{
switch (notification.type)
{
case 'started-following': return <StartedFollowing isFollowing={notification.relation.established} />;
case 'rated-post': return <RatedPost comicDataUrl={notification.post?.comic.image.dataUrl as string} />;
case 'rated-reaction': return <RatedReaction reaction={notification.reaction as ReactionView} />;
case 'added-reaction': return <AddedReaction post={notification.post as PostView} onComicClick={onComicClick} />;
case 'rated-post': return <RatedPost post={notification.post as PostView} onPostClick={onPostClick} />;
case 'rated-reaction': return <RatedReaction reaction={notification.reaction as ReactionView} onReactionClick={onReactionClick} />;
case 'added-reaction': return <AddedReaction notification={notification} onReactionClick={onReactionClick} />;
}
}

export default function Component({ notification, onFollowClick, onCreatorClick, onComicClick }: Props)
export default function Component({ notification, onFollowClick, onCreatorClick, onReactionClick, onPostClick }: Props)
{
return <Panel>
<Column gap='medium' alignX='stretch'>
Expand All @@ -40,7 +41,7 @@ export default function Component({ notification, onFollowClick, onCreatorClick,
onFollowClick={onFollowClick}
onCreatorClick={onCreatorClick}
/>
{getContent(notification, onComicClick)}
{getContent(notification, onReactionClick, onPostClick)}
</Column>
</Panel>;
}
9 changes: 6 additions & 3 deletions src/webui/components/notification/PanelList.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@

import type { AggregatedData as NotificationView } from '^/domain/notification/aggregate/types';
import type { AggregatedData as PostView } from '^/domain/post/aggregate/types';
import type { AggregatedData as ReactionView } from '^/domain/reaction/aggregate/types';
import type { AggregatedData as RelationView } from '^/domain/relation/aggregate/types';

import { Column } from '^/webui/designsystem';
Expand All @@ -11,10 +12,11 @@ type Props = {
readonly notifications: NotificationView[];
readonly onFollowClick: (relation: RelationView) => Promise<void>;
readonly onCreatorClick: (relation: RelationView) => void;
readonly onComicClick: (post: PostView) => void;
readonly onReactionClick: (reaction: ReactionView) => void;
readonly onPostClick: (post: PostView) => void;
};

export default function Component({ notifications, onFollowClick, onCreatorClick, onComicClick }: Props)
export default function Component({ notifications, onFollowClick, onCreatorClick, onReactionClick, onPostClick }: Props)
{
return <Column gap='medium' alignX='stretch'>
{
Expand All @@ -24,7 +26,8 @@ export default function Component({ notifications, onFollowClick, onCreatorClick
notification={notification}
onFollowClick={onFollowClick}
onCreatorClick={onCreatorClick}
onComicClick={onComicClick}
onReactionClick={onReactionClick}
onPostClick={onPostClick}
/>
)
}
Expand Down
13 changes: 7 additions & 6 deletions src/webui/components/notification/elementary/AddedReaction.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@

import type { AggregatedData as PostView } from '^/domain/post/aggregate/types';
import type { AggregatedData as NotificationView } from '^/domain/notification/aggregate/types';
import type { AggregatedData as ReactionView } from '^/domain/reaction/aggregate/types';
import { ClickArea, Image, Row, Text } from '^/webui/designsystem';

type Props = {
readonly post: PostView;
readonly onComicClick: (post: PostView) => void;
readonly notification: NotificationView;
readonly onReactionClick: (reaction: ReactionView) => void;
};

export default function Component({ post, onComicClick }: Props)
export default function Component({ notification, onReactionClick }: Props)
{
return <Row alignX='justify' alignY='stretch' gap='medium'>
<Text value='I added a reaction to your post.' />
<ClickArea onClick={() => onComicClick(post)}>
<Image source={post.comic.image.dataUrl} width='150px' />
<ClickArea onClick={() => onReactionClick(notification.reaction as ReactionView)}>
<Image source={notification.post?.comic.image.dataUrl as string} width='150px' />
</ClickArea>
</Row>;
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@

import { Image, Row, Text } from '^/webui/designsystem';
import { ClickArea, Image, Row, Text } from '^/webui/designsystem';

import type { AggregatedData as ReactionView } from '^/domain/reaction/aggregate/types';

type Props = {
readonly comicDataUrl: string;
readonly reaction: ReactionView;
readonly onReactionClick: (reaction: ReactionView) => void;
};

export default function Component({ comicDataUrl }: Props)
export default function Component({ reaction, onReactionClick }: Props)
{
return <Row alignX='justify' alignY='stretch' gap='medium'>
<Text value='I like your reaction.' />
<Image source={comicDataUrl} width='150px' />
<ClickArea onClick={() => onReactionClick(reaction)} >
<Image source={reaction.comic?.image.dataUrl as string} width='150px' />
</ClickArea>
</Row>;
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@

import { Border, Column, Text } from '^/webui/designsystem';
import { Border, ClickArea, Column, Text } from '^/webui/designsystem';

import type { AggregatedData as ReactionView } from '^/domain/reaction/aggregate/types';

type Props = {
readonly comment: string;
readonly reaction: ReactionView;
readonly onReactionClick: (reaction: ReactionView) => void;
};

export default function Component({ comment }: Props)
export default function Component({ reaction, onReactionClick }: Props)
{

return <Column alignX='stretch' alignY='justify' gap='medium'>
<Text value='I like your reaction.' />
<Border size='small' padding='small'>
<Text size='small' wrap='normal' value={comment} />
</Border>
<ClickArea onClick={() => onReactionClick(reaction)} >
<Border size='small' padding='small'>
<Text size='small' wrap='normal' value={reaction.comment?.message as string} />
</Border>
</ClickArea>
</Column>;
}
13 changes: 9 additions & 4 deletions src/webui/components/notification/elementary/RatedPost.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@

import { Image, Row, Text } from '^/webui/designsystem';
import { ClickArea, Image, Row, Text } from '^/webui/designsystem';

import type { AggregatedData as PostView } from '^/domain/post/aggregate/types';

type Props = {
readonly comicDataUrl: string;
readonly post: PostView;
readonly onPostClick: (post: PostView) => void;
};

export default function Component({ comicDataUrl }: Props)
export default function Component({ post, onPostClick }: Props)
{
return <Row gap='medium' alignX='justify'>
<Text value='I like your comic.' />
<Image source={comicDataUrl} width='150px' />
<ClickArea onClick={() => onPostClick(post)} >
<Image source={post.comic.image.dataUrl} width='150px' />
</ClickArea>
</Row>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ import RatedCommentReaction from '../elementary/RatedCommentReaction';

type Props = {
readonly reaction: ReactionView;
readonly onReactionClick: (reaction: ReactionView) => void;
};

export default function Component({ reaction }: Props)
export default function Component({ reaction, onReactionClick }: Props)
{
return reaction.comic !== undefined
? <RatedComicReaction comicDataUrl={reaction.comic.image.dataUrl} />
: <RatedCommentReaction comment={reaction.comment?.message as string} />;
? <RatedComicReaction reaction={reaction} onReactionClick={onReactionClick} />
: <RatedCommentReaction reaction={reaction} onReactionClick={onReactionClick} />;
}
2 changes: 1 addition & 1 deletion src/webui/components/reaction/LargePanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ type Props = {
readonly onDeleteClick: (relation: ReactionView) => Promise<void>;
};

export default function LargePanel({ reaction, onFollowClick, onCreatorClick, onRatingClick, onDeleteClick }: Props)
export default function Component({ reaction, onFollowClick, onCreatorClick, onRatingClick, onDeleteClick }: Props)
{
return <Panel padding='medium'>
<Column gap='medium' alignX='stretch'>
Expand Down
16 changes: 16 additions & 0 deletions src/webui/components/reaction/SingleReactionRow.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@

import { ClickArea, Row, Text } from '^/webui/designsystem';

type Props = {
readonly onShowClick: () => void;
};

export default function Component({ onShowClick }: Props)
{
return <Row alignY='stretch' alignX='justify' >
<Text value='single reaction' />
<ClickArea onClick={onShowClick}>
<Text value='all reactions' />
</ClickArea>
</Row>;
}
5 changes: 4 additions & 1 deletion src/webui/features/Notifications.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@ import useEstablishRelation from './hooks/useEstablishRelation';
import useNotifications from './hooks/useNotifications';
import useViewPostDetails from './hooks/useViewPostDetails';
import useViewProfile from './hooks/useViewProfile';
import useViewReactionDetails from './hooks/useViewReactionDetails';

const SCROLL_THRESHOLD = 0.7;

export default function Feature()
{
const establishRelation = useEstablishRelation();
const viewProfile = useViewProfile();
const viewReactionDetails = useViewReactionDetails();
const viewPostDetails = useViewPostDetails();

const [notifications, isLoading, isFinished, getMoreNotifications, , refresh] = useNotifications();
Expand All @@ -27,7 +29,8 @@ export default function Feature()
notifications={notifications as NotificationView[]}
onFollowClick={establishRelation}
onCreatorClick={viewProfile}
onComicClick={viewPostDetails}
onReactionClick={viewReactionDetails}
onPostClick={viewPostDetails}
/>
</ResultSet>
</ScrollLoader>
Expand Down
Loading

0 comments on commit 7800974

Please sign in to comment.