144 lines
4.5 KiB
TypeScript
144 lines
4.5 KiB
TypeScript
import React, { useState } from 'react';
|
|
import {
|
|
MainContainer,
|
|
Sidebar,
|
|
ConversationList,
|
|
Conversation,
|
|
ConversationHeader,
|
|
ChatContainer,
|
|
MessageList,
|
|
Message,
|
|
Avatar,
|
|
} from '@chatscope/chat-ui-kit-react';
|
|
import '@chatscope/chat-ui-kit-styles/dist/default/styles.min.css';
|
|
|
|
import { useSelector } from 'react-redux';
|
|
import i18n from '../../i18n';
|
|
import { geoPoint } from '../../lib/geo';
|
|
import { MapState } from '../../store/map';
|
|
import AvatarForLocation from './AvatarForLocation';
|
|
interface OsmNotesChatProps {
|
|
notes: { features: any };
|
|
}
|
|
|
|
const OsmNotesChat: React.FC<OsmNotesChatProps> = (
|
|
props: OsmNotesChatProps
|
|
) => {
|
|
const scope = useSelector((state: { map: MapState }) => state.map.scope);
|
|
|
|
const [noteIndex, setNoteIndex] = useState(0);
|
|
const conversationClickHandlerFactory = (index: number) => (event: any) => {
|
|
setNoteIndex(index);
|
|
};
|
|
|
|
const roughDistance = (a: geoPoint, b: geoPoint): number => {
|
|
const pseudoDistanceInDegrees = Math.sqrt(
|
|
(a.lat - b.lat) ** 2 + (a.lon - b.lon) ** 2
|
|
);
|
|
const metresPerDegree =
|
|
111111 * Math.cos((scope.center.lat * Math.PI) / 180);
|
|
return pseudoDistanceInDegrees * metresPerDegree;
|
|
};
|
|
|
|
const AvatarForFeature: React.FC<{
|
|
feature: any;
|
|
size: number;
|
|
as: any;
|
|
}> = (props: { feature: any; size: number; as: any }) => {
|
|
const distance = roughDistance(scope.center, {
|
|
lon: props.feature.geometry.coordinates[0],
|
|
lat: props.feature.geometry.coordinates[1],
|
|
});
|
|
return (
|
|
<Avatar size={props.size <= 50 ? 'sm' : 'lg'}>
|
|
<AvatarForLocation
|
|
location={{
|
|
lon: props.feature.geometry.coordinates[0],
|
|
lat: props.feature.geometry.coordinates[1],
|
|
}}
|
|
size={props.size}
|
|
/>
|
|
</Avatar>
|
|
);
|
|
};
|
|
|
|
return (
|
|
<div style={{ position: 'relative' }}>
|
|
<MainContainer responsive>
|
|
<Sidebar position='left' id='chat-sidebar'>
|
|
<ConversationList>
|
|
{props.notes
|
|
.features!.slice(0, 5)
|
|
.map((feature: any, index: number) => (
|
|
<Conversation
|
|
onClick={conversationClickHandlerFactory(index)}
|
|
key={feature.properties.id}
|
|
name={i18n.locationInfo!.at!(
|
|
roughDistance(scope.center, {
|
|
lon: feature.geometry.coordinates[0],
|
|
lat: feature.geometry.coordinates[1],
|
|
})
|
|
)}
|
|
info={feature.properties.status}
|
|
>
|
|
<AvatarForFeature feature={feature} size={42} as={Avatar} />
|
|
</Conversation>
|
|
))}
|
|
</ConversationList>
|
|
</Sidebar>
|
|
<ChatContainer>
|
|
<ConversationHeader>
|
|
<AvatarForFeature
|
|
feature={props.notes.features[noteIndex]}
|
|
size={68}
|
|
as={Avatar}
|
|
/>
|
|
<ConversationHeader.Content>
|
|
<span
|
|
style={{
|
|
alignSelf: 'flex-center',
|
|
}}
|
|
>
|
|
{i18n.locationInfo!.at!(
|
|
roughDistance(scope.center, {
|
|
lon: props.notes.features[noteIndex].geometry
|
|
.coordinates[0],
|
|
lat: props.notes.features[noteIndex].geometry
|
|
.coordinates[1],
|
|
})
|
|
)}
|
|
</span>
|
|
</ConversationHeader.Content>
|
|
</ConversationHeader>
|
|
<MessageList>
|
|
{noteIndex < props.notes.features.length &&
|
|
props.notes.features[noteIndex].properties.comments.map(
|
|
(comment: any, index: number) => (
|
|
<Message
|
|
key={`${props.notes.features[noteIndex].properties.id}/${index}`}
|
|
model={{
|
|
direction: 'incoming',
|
|
position: 'single',
|
|
sender: comment.user,
|
|
sentTime: comment.date,
|
|
payload: comment.html,
|
|
}}
|
|
>
|
|
<Message.Header
|
|
sender={comment.user}
|
|
sentTime={comment.date}
|
|
/>
|
|
<Message.Footer sentTime={comment.action} />
|
|
<Avatar>{comment.user ? comment.user : '??'}</Avatar>
|
|
</Message>
|
|
)
|
|
)}
|
|
</MessageList>
|
|
</ChatContainer>
|
|
</MainContainer>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default OsmNotesChat;
|