change(ui) - assist recordings pagination api
This commit is contained in:
parent
9fb1735d2c
commit
b78b05791e
4 changed files with 86 additions and 55 deletions
|
|
@ -5,31 +5,45 @@ import RecordingsSearch from './RecordingsSearch';
|
||||||
import RecordingsList from './RecordingsList';
|
import RecordingsList from './RecordingsList';
|
||||||
import { useStore } from 'App/mstore';
|
import { useStore } from 'App/mstore';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
import SelectDateRange from 'Shared/SelectDateRange/SelectDateRange';
|
||||||
|
import Period from 'Types/app/period';
|
||||||
|
import { observer } from 'mobx-react-lite';
|
||||||
|
|
||||||
function Recordings({ userId }: { userId: string }) {
|
interface Props {
|
||||||
|
userId: string;
|
||||||
|
filter: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Recordings(props: Props) {
|
||||||
|
const { userId } = props;
|
||||||
const { recordingsStore } = useStore();
|
const { recordingsStore } = useStore();
|
||||||
|
|
||||||
const recordingsOwner = [
|
const recordingsOwner = [
|
||||||
{ value: '0', label: 'All Recordings' },
|
{ value: '0', label: 'All Recordings' },
|
||||||
{ value: userId, label: 'My Recordings' },
|
{ value: userId, label: 'My Recordings' }
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const onDateChange = (e: any) => {
|
||||||
|
recordingsStore.updateTimestamps(e);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ maxWidth: '1300px', margin: 'auto' }} className="bg-white rounded py-4 border">
|
<div style={{ maxWidth: '1300px', margin: 'auto' }} className='bg-white rounded py-4 border'>
|
||||||
<div className="flex items-center mb-4 justify-between px-6">
|
<div className='flex items-center mb-4 justify-between px-6'>
|
||||||
<div className="flex items-baseline mr-3">
|
<div className='flex items-baseline mr-3'>
|
||||||
<PageTitle title="Recordings" />
|
<PageTitle title='Recordings' />
|
||||||
</div>
|
</div>
|
||||||
<div className="ml-auto flex items-center">
|
<div className='ml-auto flex items-center'>
|
||||||
|
<SelectDateRange period={recordingsStore.period} onChange={onDateChange} right={true} />
|
||||||
<Select
|
<Select
|
||||||
name="recsOwner"
|
name='recsOwner'
|
||||||
plain
|
plain
|
||||||
right
|
right
|
||||||
options={recordingsOwner}
|
options={recordingsOwner}
|
||||||
onChange={({ value }) => recordingsStore.setUserId(value.value)}
|
onChange={({ value }) => recordingsStore.setUserId(value.value)}
|
||||||
defaultValue={recordingsOwner[0].value}
|
defaultValue={recordingsOwner[0].value}
|
||||||
/>
|
/>
|
||||||
<div className="ml-4 w-1/4" style={{ minWidth: 300 }}>
|
<div className='ml-4 w-1/4' style={{ minWidth: 300 }}>
|
||||||
<RecordingsSearch />
|
<RecordingsSearch />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -39,6 +53,6 @@ function Recordings({ userId }: { userId: string }) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect((state: any) => ({ userId: state.getIn(['user', 'account', 'id']) }))(
|
export default connect((state: any) => ({
|
||||||
Recordings
|
userId: state.getIn(['user', 'account', 'id'])
|
||||||
);
|
}))(observer(Recordings));
|
||||||
|
|
|
||||||
|
|
@ -1,42 +1,38 @@
|
||||||
import { observer } from 'mobx-react-lite';
|
import { observer } from 'mobx-react-lite';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { NoContent, Pagination, Icon, Button } from 'UI';
|
import { NoContent, Pagination, Loader } from 'UI';
|
||||||
import { useStore } from 'App/mstore';
|
import { useStore } from 'App/mstore';
|
||||||
import { filterList } from 'App/utils';
|
|
||||||
import { sliceListPerPage } from 'App/utils';
|
|
||||||
import RecordsListItem from './RecordsListItem';
|
import RecordsListItem from './RecordsListItem';
|
||||||
import AnimatedSVG, { ICONS } from 'Shared/AnimatedSVG/AnimatedSVG';
|
import AnimatedSVG, { ICONS } from 'Shared/AnimatedSVG/AnimatedSVG';
|
||||||
|
|
||||||
function RecordingsList() {
|
function RecordingsList() {
|
||||||
const { recordingsStore } = useStore();
|
const { recordingsStore } = useStore();
|
||||||
const [shownRecordings, setRecordings] = React.useState<any[]>([]);
|
// const [shownRecordings, setRecordings] = React.useState<any[]>([]);
|
||||||
const recordings = recordingsStore.recordings;
|
const recordings = recordingsStore.recordings;
|
||||||
const recordsSearch = recordingsStore.search;
|
const recordsSearch = recordingsStore.search;
|
||||||
|
const page = recordingsStore.page;
|
||||||
|
const pageSize = recordingsStore.pageSize;
|
||||||
|
const total = recordingsStore.total;
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
recordingsStore.fetchRecordings();
|
recordingsStore.fetchRecordings();
|
||||||
}, []);
|
}, [page, recordingsStore.period, recordsSearch, recordingsStore.userId]);
|
||||||
|
|
||||||
React.useEffect(() => {
|
const length = recordings.length;
|
||||||
setRecordings(filterList(recordings, recordsSearch, ['createdBy', 'name']));
|
|
||||||
}, [recordsSearch]);
|
|
||||||
|
|
||||||
const list = recordsSearch !== '' ? shownRecordings : recordings;
|
|
||||||
const length = list.length;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NoContent
|
<NoContent
|
||||||
show={length === 0}
|
show={length === 0}
|
||||||
title={
|
title={
|
||||||
<div className="flex flex-col items-center justify-center">
|
<div className='flex flex-col items-center justify-center'>
|
||||||
<AnimatedSVG name={ICONS.NO_RECORDINGS} size={180} />
|
<AnimatedSVG name={ICONS.NO_RECORDINGS} size={180} />
|
||||||
<div className="text-center text-gray-600 mt-4">
|
<div className='text-center text-gray-600 mt-4'>
|
||||||
{recordsSearch !== '' ? 'No matching results' : 'No recordings available yet.'}
|
{recordsSearch !== '' ? 'No matching results' : 'No recordings available yet.'}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
subtext={
|
subtext={
|
||||||
<div className="text-center flex justify-center items-center flex-col">
|
<div className='text-center flex justify-center items-center flex-col'>
|
||||||
<span>
|
<span>
|
||||||
Record your co-browsing sessions and share them with your team for product feedback or
|
Record your co-browsing sessions and share them with your team for product feedback or
|
||||||
training purposes.
|
training purposes.
|
||||||
|
|
@ -44,32 +40,34 @@ function RecordingsList() {
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div className="mt-3 border-b">
|
<div className='mt-3 border-b'>
|
||||||
<div className="grid grid-cols-12 py-2 font-medium px-6">
|
<Loader loading={recordingsStore.loading}>
|
||||||
<div className="col-span-8">Name</div>
|
<div className='grid grid-cols-12 py-2 font-medium px-6'>
|
||||||
<div className="col-span-4">Recorded by</div>
|
<div className='col-span-8'>Name</div>
|
||||||
</div>
|
<div className='col-span-4'>Recorded by</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{sliceListPerPage(list, recordingsStore.page - 1, recordingsStore.pageSize).map(
|
{recordings.map(
|
||||||
(record: any) => (
|
(record: any) => (
|
||||||
<React.Fragment key={record.recordId}>
|
<React.Fragment key={record.recordId}>
|
||||||
<RecordsListItem record={record} />
|
<RecordsListItem record={record} />
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
|
</Loader>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="w-full flex items-center justify-between pt-4 px-6">
|
<div className='w-full flex items-center justify-between pt-4 px-6'>
|
||||||
<div className="text-disabled-text">
|
<div className='text-disabled-text'>
|
||||||
Showing{' '}
|
Showing{' '}
|
||||||
<span className="font-semibold">{Math.min(list.length, recordingsStore.pageSize)}</span>{' '}
|
<span className='font-semibold'>{Math.min(length, pageSize)}</span>{' '}
|
||||||
out of <span className="font-semibold">{list.length}</span> Recording
|
out of <span className='font-semibold'>{total}</span> Recording
|
||||||
</div>
|
</div>
|
||||||
<Pagination
|
<Pagination
|
||||||
page={recordingsStore.page}
|
page={page}
|
||||||
totalPages={Math.ceil(length / recordingsStore.pageSize)}
|
totalPages={Math.ceil(total / pageSize)}
|
||||||
onPageChange={(page) => recordingsStore.updatePage(page)}
|
onPageChange={(page) => recordingsStore.updatePage(page)}
|
||||||
limit={recordingsStore.pageSize}
|
limit={pageSize}
|
||||||
debounceRequest={100}
|
debounceRequest={100}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,34 +1,48 @@
|
||||||
import { makeAutoObservable } from 'mobx';
|
import { makeAutoObservable } from 'mobx';
|
||||||
import { recordingsService } from 'App/services';
|
import { recordingsService } from 'App/services';
|
||||||
import { IRecord } from 'App/services/RecordingsService';
|
import { IRecord } from 'App/services/RecordingsService';
|
||||||
|
import Period, { LAST_7_DAYS } from 'Types/app/period';
|
||||||
|
|
||||||
export default class RecordingsStore {
|
export default class RecordingsStore {
|
||||||
recordings: IRecord[] = [];
|
recordings: IRecord[] = [];
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
|
|
||||||
page = 1;
|
page = 1;
|
||||||
pageSize = 15;
|
total: number = 0;
|
||||||
|
pageSize = 5;
|
||||||
order: 'desc' | 'asc' = 'desc';
|
order: 'desc' | 'asc' = 'desc';
|
||||||
search = '';
|
search = '';
|
||||||
// later we will add search by user id
|
// later we will add search by user id
|
||||||
userId = '0';
|
userId = '0';
|
||||||
|
startTimestamp = 0;
|
||||||
|
endTimestamp = 0;
|
||||||
|
rangeName: string = 'LAST_24_HOURS';
|
||||||
|
period: any = Period({ rangeName: LAST_7_DAYS });
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
makeAutoObservable(this);
|
makeAutoObservable(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
setRecordings(records: IRecord[]) {
|
setRecordings(records: IRecord[], total?: number) {
|
||||||
|
this.total = total || 0;
|
||||||
this.recordings = records;
|
this.recordings = records;
|
||||||
}
|
}
|
||||||
|
|
||||||
setUserId(userId: string) {
|
setUserId(userId: string) {
|
||||||
this.userId = userId;
|
this.userId = userId;
|
||||||
this.fetchRecordings();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updateSearch(val: string) {
|
updateSearch(val: string) {
|
||||||
this.search = val;
|
this.search = val;
|
||||||
|
this.page = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateTimestamps(period: any): void {
|
||||||
|
const { start, end, rangeName } = period;
|
||||||
|
this.period = Period({ start, end, rangeName });
|
||||||
|
this.page = 1;
|
||||||
|
}
|
||||||
|
|
||||||
updatePage(page: number) {
|
updatePage(page: number) {
|
||||||
this.page = page;
|
this.page = page;
|
||||||
}
|
}
|
||||||
|
|
@ -38,15 +52,17 @@ export default class RecordingsStore {
|
||||||
page: this.page,
|
page: this.page,
|
||||||
limit: this.pageSize,
|
limit: this.pageSize,
|
||||||
order: this.order,
|
order: this.order,
|
||||||
search: this.search,
|
query: this.search,
|
||||||
userId: this.userId === '0' ? undefined : this.userId,
|
userId: this.userId === '0' ? undefined : this.userId,
|
||||||
|
startTimestamp: this.period.start,
|
||||||
|
endTimestamp: this.period.end
|
||||||
};
|
};
|
||||||
|
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
try {
|
try {
|
||||||
const recordings = await recordingsService.fetchRecordings(filter);
|
const response: { records: [], total: number } = await recordingsService.fetchRecordings(filter);
|
||||||
this.setRecordings(recordings);
|
this.setRecordings(response.records, response.total);
|
||||||
return recordings;
|
return response.records;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
} finally {
|
} finally {
|
||||||
|
|
@ -54,7 +70,7 @@ export default class RecordingsStore {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fetchRecordingUrl(id: number): Promise<string> {
|
async fetchRecordingUrl(id: number): Promise<string | undefined> {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
try {
|
try {
|
||||||
const recording = await recordingsService.fetchRecording(id);
|
const recording = await recordingsService.fetchRecording(id);
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,10 @@ interface FetchFilter {
|
||||||
page: number;
|
page: number;
|
||||||
limit: number;
|
limit: number;
|
||||||
order: 'asc' | 'desc';
|
order: 'asc' | 'desc';
|
||||||
search: string;
|
query: string;
|
||||||
|
startTimestamp: number;
|
||||||
|
endTimestamp: number;
|
||||||
|
userId?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IRecord {
|
export interface IRecord {
|
||||||
|
|
@ -57,7 +60,7 @@ export default class RecordingsService {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchRecordings(filters: FetchFilter): Promise<IRecord[]> {
|
fetchRecordings(filters: FetchFilter): Promise<any> {
|
||||||
return this.client.post(`/assist/records`, filters).then((r) => {
|
return this.client.post(`/assist/records`, filters).then((r) => {
|
||||||
return r.json().then((j) => j.data);
|
return r.json().then((j) => j.data);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue