Skip to content

Commit 3b8f2e1

Browse files
Geolocation attachment
1 parent 06b3bd3 commit 3b8f2e1

File tree

5 files changed

+88
-32
lines changed

5 files changed

+88
-32
lines changed

examples/vite/src/App.tsx

Lines changed: 9 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import {
2020
ChatView,
2121
useChatContext,
2222
useLiveLocationSharingManager,
23-
Attachment,
2423
} from 'stream-chat-react';
2524
import 'stream-chat-react/css/v2/index.css';
2625

@@ -90,7 +89,7 @@ const ShareLiveLocation = () => {
9089
});
9190
},
9291
console.warn,
93-
{ timeout: 200 },
92+
{ timeout: 2000 },
9493
);
9594
}}
9695
>
@@ -116,7 +115,10 @@ const watchLocationTimed: LiveLocationManagerConstructorParameters['watchLocatio
116115
});
117116
}, 5000);
118117

119-
return () => clearInterval(timer);
118+
return () => {
119+
clearInterval(timer);
120+
console.log('cleanup');
121+
};
120122
};
121123

122124
const App = () => {
@@ -126,13 +128,11 @@ const App = () => {
126128
userData: { id: userId },
127129
});
128130

129-
const manager = useLiveLocationSharingManager({
130-
client: chatClient ?? undefined,
131-
watchLocation: watchLocationTimed,
131+
useLiveLocationSharingManager({
132+
client: chatClient,
133+
watchLocation: watchLocationNormal,
132134
});
133135

134-
// const s = useStateStore(manager?.state)
135-
136136
if (!chatClient) return <>Loading...</>;
137137

138138
return (
@@ -148,21 +148,7 @@ const App = () => {
148148
showChannelSearch
149149
additionalChannelSearchProps={{ searchForChannels: true }}
150150
/>
151-
<Channel
152-
Attachment={(props) => {
153-
const [attachment] = props.attachments ?? [];
154-
155-
if (attachment?.type === 'live_location') {
156-
return (
157-
<div style={{ padding: 25 }}>
158-
lat: {attachment.latitude}, lng: {attachment.longitude}
159-
</div>
160-
);
161-
}
162-
163-
return <Attachment {...props} />;
164-
}}
165-
>
151+
<Channel>
166152
<Window>
167153
<ChannelHeader Avatar={ChannelAvatar} />
168154
<MessageList returnAllReadData />

src/components/Attachment/Attachment.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
CardContainer,
1818
FileContainer,
1919
GalleryContainer,
20+
GeolocationContainer,
2021
ImageContainer,
2122
MediaContainer,
2223
UnsupportedAttachmentContainer,
@@ -38,10 +39,10 @@ const CONTAINER_MAP = {
3839
audio: AudioContainer,
3940
card: CardContainer,
4041
file: FileContainer,
42+
geolocation: GeolocationContainer,
4143
media: MediaContainer,
4244
unsupported: UnsupportedAttachmentContainer,
4345
voiceRecording: VoiceRecordingContainer,
44-
// geolocation: () => <div></div>,
4546
} as const;
4647

4748
export const ATTACHMENT_GROUPS_ORDER = [
@@ -52,6 +53,7 @@ export const ATTACHMENT_GROUPS_ORDER = [
5253
'audio',
5354
'voiceRecording',
5455
'file',
56+
'geolocation',
5557
'unsupported',
5658
] as const;
5759

@@ -72,6 +74,9 @@ export type AttachmentProps<
7274
File?: React.ComponentType<FileAttachmentProps<StreamChatGenerics>>;
7375
/** Custom UI component for displaying a gallery of image type attachments, defaults to and accepts same props as: [Gallery](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Gallery/Gallery.tsx) */
7476
Gallery?: React.ComponentType<GalleryProps<StreamChatGenerics>>;
77+
Geolocation?: React.ComponentType<{
78+
attachment: StreamAttachment<StreamChatGenerics>;
79+
}>;
7580
/** Custom UI component for displaying an image type attachment, defaults to and accepts same props as: [Image](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Gallery/Image.tsx) */
7681
Image?: React.ComponentType<ImageProps>;
7782
/** Optional flag to signal that an attachment is a displayed as a part of a quoted message */
@@ -145,6 +150,7 @@ const renderGroupedAttachments = <
145150
image: [],
146151
// eslint-disable-next-line sort-keys
147152
gallery: [],
153+
geolocation: [],
148154
voiceRecording: [],
149155
},
150156
);
@@ -184,6 +190,8 @@ const getAttachmentType = <
184190
return 'voiceRecording';
185191
} else if (isFileAttachment(attachment)) {
186192
return 'file';
193+
} else if (attachment.type === 'live_location' || attachment.type === 'static_location') {
194+
return 'geolocation';
187195
}
188196

189197
return 'unsupported';

src/components/Attachment/AttachmentContainer.tsx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { Gallery as DefaultGallery, ImageComponent as DefaultImage } from '../Ga
1111
import { Card as DefaultCard } from './Card';
1212
import { FileAttachment as DefaultFile } from './FileAttachment';
1313
import { UnsupportedAttachment as DefaultUnsupportedAttachment } from './UnsupportedAttachment';
14+
import { Geolocation as DefaultGeolocation } from './Geolocation';
1415
import {
1516
AttachmentComponentType,
1617
GalleryAttachment,
@@ -318,6 +319,17 @@ export const MediaContainer = <
318319
);
319320
};
320321

322+
export const GeolocationContainer = <
323+
StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics
324+
>({
325+
attachment,
326+
Geolocation = DefaultGeolocation,
327+
}: RenderAttachmentProps<StreamChatGenerics>) => (
328+
<>
329+
<Geolocation attachment={attachment} />
330+
</>
331+
);
332+
321333
export const UnsupportedAttachmentContainer = <
322334
StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics
323335
>({
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import React from 'react';
2+
import type { Attachment, DefaultGenerics, ExtendableGenerics } from 'stream-chat';
3+
import { useChatContext, useMessageContext } from '../../context';
4+
5+
export const Geolocation = <SCG extends ExtendableGenerics = DefaultGenerics>({
6+
attachment,
7+
}: {
8+
attachment: Attachment<SCG>;
9+
}) => {
10+
const { channel } = useChatContext();
11+
const { isMyMessage, message } = useMessageContext();
12+
13+
const stoppedSharing = !!attachment.stopped_sharing;
14+
const expired: boolean =
15+
typeof attachment.end_time === 'string' && Date.now() > new Date(attachment.end_time).getTime();
16+
17+
return (
18+
<div
19+
style={{
20+
display: 'flex',
21+
flexDirection: 'column',
22+
gap: 10,
23+
paddingBlock: 15,
24+
paddingInline: 10,
25+
width: 'auto',
26+
}}
27+
>
28+
{attachment.type === 'live_location' && !stoppedSharing && !expired && isMyMessage() && (
29+
<button
30+
onClick={() =>
31+
channel?.stopLiveLocationSharing({
32+
attachments: message.attachments,
33+
id: message.id,
34+
type: message.type,
35+
})
36+
}
37+
>
38+
Stop sharing
39+
</button>
40+
)}
41+
{/* TODO: {MAP} */}
42+
<span>
43+
lat: {attachment.latitude}, lng: {attachment.longitude}
44+
</span>
45+
{(stoppedSharing || expired) && <span style={{ fontSize: 12 }}>Location sharing ended</span>}
46+
</div>
47+
);
48+
};

src/components/Attachment/hooks/useLiveLocationSharingManager.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,23 @@
11
import { LiveLocationManager } from 'stream-chat';
2-
import type { LiveLocationManagerConstructorParameters } from 'stream-chat';
32
import { useEffect, useMemo } from 'react';
3+
import type {
4+
ExtendableGenerics,
5+
LiveLocationManagerConstructorParameters,
6+
StreamChat,
7+
} from 'stream-chat';
48

5-
type PartialKeys<T, K extends keyof T> = {
6-
[L in keyof T]: L extends K ? T[L] | undefined : T[L];
7-
};
8-
9-
export const useLiveLocationSharingManager = ({
9+
export const useLiveLocationSharingManager = <SCG extends ExtendableGenerics>({
1010
client,
1111
retrieveAndDeserialize,
1212
serializeAndStore,
1313
watchLocation,
14-
}: PartialKeys<LiveLocationManagerConstructorParameters, 'client'>) => {
14+
}: Omit<LiveLocationManagerConstructorParameters<SCG>, 'client'> & {
15+
client?: StreamChat<SCG> | null;
16+
}) => {
1517
const manager = useMemo(() => {
1618
if (!client) return null;
1719

18-
return new LiveLocationManager({
20+
return new LiveLocationManager<SCG>({
1921
client,
2022
retrieveAndDeserialize,
2123
serializeAndStore,

0 commit comments

Comments
 (0)