import ThingsFilter from '@/components/shared/ThingFilterModal'; import { DEFAULT_PAGE_SIZE } from '@/constants'; import { apiDeleteUserThingPolicy, apiGetThingPolicyByUser, apiShareThingToUser, } from '@/services/master/ThingController'; import { DeleteOutlined, ShareAltOutlined } from '@ant-design/icons'; import { ActionType, FooterToolbar, ProList, ProListMetas, } from '@ant-design/pro-components'; import { FormattedMessage, useIntl } from '@umijs/max'; import { Button, Checkbox, GetProp, message, Popconfirm, Tag, Typography, } from 'antd'; import { useRef, useState } from 'react'; const { Paragraph } = Typography; type PolicyShareDefault = { read: boolean; write: boolean; delete: boolean; }; type ShareThingProps = { user: MasterModel.UserResponse | null; }; const ShareThing = ({ user }: ShareThingProps) => { const listActionRef = useRef(); const intl = useIntl(); const [messageApi, contextHolder] = message.useMessage(); const [selectedRowsState, setSelectedRows] = useState< MasterModel.ThingPolicy[] >([]); const [thingPolicy, setThingPolicy] = useState([]); const [shareThingModalVisible, setShareThingModalVisible] = useState(false); const [policyShare, setPolicyShare] = useState({ read: true, write: true, delete: true, }); const getPolicyInfo = ( policy: MasterModel.Policy, ): { color: string; text: string } => { switch (policy) { case 'read': return { color: 'blue', text: intl.formatMessage({ id: 'master.users.things.relation.read', defaultMessage: 'Read', }), }; case 'write': return { color: 'gold', text: intl.formatMessage({ id: 'master.users.things.relation.write', defaultMessage: 'Write', }), }; case 'delete': return { color: 'red', text: intl.formatMessage({ id: 'master.users.things.relation.delete', defaultMessage: 'Delete', }), }; default: return { color: 'default', text: policy }; } }; const columns: ProListMetas = { title: { dataIndex: 'name', render: (_, record: MasterModel.ThingPolicy) => ( {record?.thing_name} ), }, subTitle: { dataIndex: 'metadata.external_id', render: (_, record: MasterModel.ThingPolicy) => ( {record?.external_id} ), }, description: { dataIndex: 'policies', render: (_, record: MasterModel.ThingPolicy) => { return record?.policies?.map((policy) => { const info = getPolicyInfo(policy); return ( {info.text} ); }); }, }, }; const handleShareThings = async (thingIds: string[]) => { const thingsFiltered = thingIds.filter((thingId) => { return !thingPolicy.find((thing) => thing.thing_id === thingId); }); if (thingsFiltered.length === 0) return; const key = 'share'; try { messageApi.open({ type: 'loading', content: intl.formatMessage({ id: 'master.users.things.sharing', defaultMessage: 'Sharing devices...', }), key, }); const allShare = thingsFiltered.map(async (thingId) => { const resp = await apiShareThingToUser( thingId, user?.id || '', Object.keys(policyShare).filter( (key) => policyShare[key as keyof PolicyShareDefault], ), ); }); await Promise.all(allShare); messageApi.open({ type: 'success', content: intl.formatMessage({ id: 'master.users.thing.share.success', defaultMessage: 'Share successfully and will refresh soon', }), key, }); await new Promise((resolve) => { setTimeout(resolve, 500); }); if (listActionRef.current) { listActionRef.current.reload(); } } catch (error) { console.error('Error when share thing: ', error); messageApi.open({ type: 'error', content: intl.formatMessage({ id: 'master.users.thing.share.fail', defaultMessage: 'Share failed, please try again!', }), key, }); } }; const onChange: GetProp = ( checkedValues, ) => { setPolicyShare({ read: checkedValues.includes('read'), write: checkedValues.includes('write'), delete: checkedValues.includes('delete'), }); }; const handleUnshare = async (selectedRows: MasterModel.ThingPolicy[]) => { if (!selectedRows) return true; const key = 'unshare'; try { messageApi.open({ type: 'loading', content: intl.formatMessage({ id: 'master.users.things.unsharing', defaultMessage: 'Unsharing devices...', }), key, }); const allUnshare = selectedRows.map(async (row) => { const resp = await apiDeleteUserThingPolicy( row?.thing_id || '', user?.id || '', ); }); await Promise.all(allUnshare); messageApi.open({ type: 'success', content: intl.formatMessage({ id: 'master.users.thing.unshare.success', defaultMessage: 'Unshare successfully and will refresh soon', }), key, }); await new Promise((resolve) => { setTimeout(resolve, 500); }); return true; } catch (error) { console.error('Error when unshare thing: ', error); messageApi.open({ type: 'error', content: intl.formatMessage({ id: 'master.users.thing.unshare.fail', defaultMessage: 'Unshare failed, please try again!', }), key, }); return false; } }; return ( <> {contextHolder} thing.thing_id!)} disabled extra={ policyShare[key as keyof PolicyShareDefault], )} onChange={onChange} /> } onSubmit={handleShareThings} /> headerTitle={intl.formatMessage({ id: 'master.users.things.list', defaultMessage: 'List things', })} actionRef={listActionRef} toolBarRender={() => [ , ]} pagination={{ pageSize: DEFAULT_PAGE_SIZE, }} metas={columns} request={async (params) => { const { current, pageSize } = params; const query = { type: 'sub', id: user?.id || '', }; if (user?.id) { const offset = current === 1 ? 0 : (current! - 1) * pageSize!; const policyBody: Partial = { offset: offset, limit: pageSize, }; const resp = await apiGetThingPolicyByUser(policyBody, user.id); if (resp.things) { setThingPolicy(resp.things); return Promise.resolve({ success: true, data: resp.things, total: resp.total, }); } else { return { success: false, data: [], total: 0, }; } } return Promise.resolve({ success: false, data: [], total: 0, }); }} rowKey="external_id" search={false} rowSelection={{ selectedRowKeys: selectedRowsState .map((row) => row.external_id) .filter((id): id is string => id !== undefined), onChange: (_, selectedRows: MasterModel.ThingPolicy[]) => { setSelectedRows(selectedRows); }, }} /> {selectedRowsState?.length > 0 && ( {' '} {selectedRowsState.length} {' '} } > { const success = await handleUnshare(selectedRowsState); if (success) { setSelectedRows([]); if (listActionRef.current) { listActionRef.current.reload(); } } }} > )} ); }; export default ShareThing;