From 93ce8560fa19c3a91de99643fdbbe4f895a47b84 Mon Sep 17 00:00:00 2001 From: crupest Date: Thu, 11 Jun 2020 17:27:15 +0800 Subject: feat(front): Service worker is coming! --- .../ClientApp/src/app/timeline/TimelineMember.tsx | 196 +++++++++++++++++++++ 1 file changed, 196 insertions(+) create mode 100644 Timeline/ClientApp/src/app/timeline/TimelineMember.tsx (limited to 'Timeline/ClientApp/src/app/timeline/TimelineMember.tsx') diff --git a/Timeline/ClientApp/src/app/timeline/TimelineMember.tsx b/Timeline/ClientApp/src/app/timeline/TimelineMember.tsx new file mode 100644 index 00000000..f9747b4d --- /dev/null +++ b/Timeline/ClientApp/src/app/timeline/TimelineMember.tsx @@ -0,0 +1,196 @@ +import React, { useState } from 'react'; +import { useTranslation } from 'react-i18next'; + +import { User } from '../data/user'; + +import SearchInput from '../common/SearchInput'; +import { + Container, + ListGroup, + ListGroupItem, + Modal, + Row, + Col, + Button, +} from 'reactstrap'; + +export interface TimelineMemberCallbacks { + onCheckUser: (username: string) => Promise; + onAddUser: (user: User) => Promise; + onRemoveUser: (username: string) => void; +} + +export interface TimelineMemberProps { + members: User[]; + edit: TimelineMemberCallbacks | null | undefined; +} + +const TimelineMember: React.FC = (props) => { + const { t } = useTranslation(); + + const [userSearchText, setUserSearchText] = useState(''); + const [userSearchState, setUserSearchState] = useState< + | { + type: 'user'; + data: User; + } + | { type: 'error'; data: string } + | { type: 'loading' } + | { type: 'init' } + >({ type: 'init' }); + + const members = props.members; + + return ( + + + {members.map((member, index) => ( + + + + + + + {member.nickname} + + {'@' + member.username} + + + {(() => { + if (index === 0) { + return null; + } + const onRemove = props.edit?.onRemoveUser; + if (onRemove == null) { + return null; + } + return ( + + ); + })()} + + + ))} + + {(() => { + const edit = props.edit; + if (edit != null) { + return ( + <> + { + setUserSearchText(v); + }} + loading={userSearchState.type === 'loading'} + onButtonClick={() => { + if (userSearchText === '') { + setUserSearchState({ + type: 'error', + data: 'login.emptyUsername', + }); + return; + } + + setUserSearchState({ type: 'loading' }); + edit.onCheckUser(userSearchText).then( + (u) => { + if (u == null) { + setUserSearchState({ + type: 'error', + data: 'timeline.userNotExist', + }); + } else { + setUserSearchState({ type: 'user', data: u }); + } + }, + (e) => { + setUserSearchState({ + type: 'error', + data: `${e as string}`, + }); + } + ); + }} + /> + {(() => { + if (userSearchState.type === 'user') { + const u = userSearchState.data; + const addable = + members.findIndex((m) => m.username === u.username) === -1; + return ( + <> + {!addable ? ( +

{t('timeline.member.alreadyMember')}

+ ) : null} + + + + + + + {u.nickname} + + {'@' + u.username} + + + + + + + ); + } else if (userSearchState.type === 'error') { + return ( +

{t(userSearchState.data)}

+ ); + } + })()} + + ); + } else { + return null; + } + })()} +
+ ); +}; + +export default TimelineMember; + +export interface TimelineMemberDialogProps extends TimelineMemberProps { + open: boolean; + onClose: () => void; +} + +export const TimelineMemberDialog: React.FC = ( + props +) => { + return ( + + + + ); +}; -- cgit v1.2.3