import React, { useState, useEffect, useMemo } from 'react';
import { Table, Popover, Input, Descriptions, Tag, Image, Empty, Button, Toast, Divider } from '@douyinfe/semi-ui';
import { useActions, useSelector } from '../../../services/state/store.js';
import { IconClose, IconDelete, IconSearch, IconStar, IconStarStroked, IconTick } from '@douyinfe/semi-icons';
import * as timeService from '../../../services/time/timeService.js';
import debounce from 'lodash/debounce';
import no_image from '../../../assets/no_image.jpg';
import './ListingsTable.less';
import { format } from '../../../services/time/timeService.js';
import { IllustrationNoResult, IllustrationNoResultDark } from '@douyinfe/semi-illustrations';
import { xhrDelete, xhrPost } from '../../../services/xhr.js';
import ListingsFilter from './ListingsFilter.jsx';
const columns = [
{
title: 'Watchlist',
width: 110,
dataIndex: 'isWatched',
sorter: true,
render: (id, row) => {
return (
) : (
)
}
theme="borderless"
size="small"
onClick={async () => {
try {
await xhrPost('/api/listings/watch', { listingId: row.id });
Toast.success(row.isWatched === 1 ? 'Listing removed from Watchlist' : 'Listing added to Watchlist');
row.reloadTable();
} catch (e) {
console.error(e);
Toast.error('Failed to operate Watchlist');
}
}}
/>
}
theme="borderless"
size="small"
type="danger"
onClick={async () => {
try {
await xhrDelete('/api/listings/', { ids: [row.id] });
Toast.success('Listing(s) successfully removed');
row.reloadTable();
} catch (error) {
Toast.error(error);
}
}}
/>
);
},
},
{
title: 'State',
dataIndex: 'is_active',
width: 84,
sorter: true,
render: (value) => {
return value ? (
) : (
);
},
},
{
title: 'Job-Name',
sorter: true,
ellipsis: true,
dataIndex: 'job_name',
width: 150,
},
{
title: 'Listing date',
width: 130,
dataIndex: 'created_at',
sorter: true,
render: (text) => timeService.format(text, false),
},
{
title: 'Provider',
width: 130,
dataIndex: 'provider',
sorter: true,
render: (text) => text.charAt(0).toUpperCase() + text.slice(1),
},
{
title: 'Price',
width: 110,
dataIndex: 'price',
sorter: true,
render: (text) => text + ' €',
},
{
title: 'Address',
width: 150,
dataIndex: 'address',
sorter: true,
},
{
title: 'Title',
dataIndex: 'title',
sorter: true,
ellipsis: true,
render: (text, row) => {
return (
{text}
);
},
},
];
const empty = (
}
darkModeImage={}
description="No listings available."
/>
);
export default function ListingsTable() {
const tableData = useSelector((state) => state.listingsTable);
const actions = useActions();
const [page, setPage] = useState(1);
const pageSize = 10;
const [sortData, setSortData] = useState({});
const [freeTextFilter, setFreeTextFilter] = useState(null);
const [watchListFilter, setWatchListFilter] = useState(null);
const [jobNameFilter, setJobNameFilter] = useState(null);
const [activityFilter, setActivityFilter] = useState(null);
const [providerFilter, setProviderFilter] = useState(null);
const [imageWidth, setImageWidth] = useState('100%');
const handlePageChange = (_page) => {
setPage(_page);
};
const loadTable = () => {
let sortfield = null;
let sortdir = null;
if (sortData != null && Object.keys(sortData).length > 0) {
sortfield = sortData.field;
sortdir = sortData.direction;
}
actions.listingsTable.getListingsTable({
page,
pageSize,
sortfield,
sortdir,
freeTextFilter,
filter: { watchListFilter, jobNameFilter, activityFilter, providerFilter },
});
};
useEffect(() => {
loadTable();
}, [page, sortData, freeTextFilter, providerFilter, activityFilter, jobNameFilter, watchListFilter]);
const handleFilterChange = useMemo(() => debounce((value) => setFreeTextFilter(value), 500), []);
const expandRowRender = (record) => {
return (
{record.image_url == null ? (
) : (
{
setImageWidth('180px');
}}
fallback={}
/>
)}
{record.is_active ? 'Yes' : 'No'}
Link to Listing
{format(record.created_at)}
{record.price} €
{record.title}
{record.description == null ? 'No description available' : record.description}
);
};
return (