List other user's tunes and profile, closes: #858
This commit is contained in:
parent
d10dabf04e
commit
328f8e12a1
|
@ -63,6 +63,7 @@ const ResetPasswordConfirmation = lazy(() => import('./pages/auth/ResetPasswordC
|
|||
const EmailVerification = lazy(() => import('./pages/auth/EmailVerification'));
|
||||
const OauthCallback = lazy(() => import('./pages/auth/OauthCallback'));
|
||||
const About = lazy(() => import('./pages/About'));
|
||||
const User = lazy(() => import('./pages/User'));
|
||||
|
||||
const { Content } = Layout;
|
||||
|
||||
|
@ -202,6 +203,7 @@ const App = ({ ui, tuneData }: { ui: UIState, tuneData: TuneDataState }) => {
|
|||
<Route path={Routes.PROFILE} element={<ContentFor element={<Profile />} />} />
|
||||
<Route path={Routes.RESET_PASSWORD} element={<ContentFor element={<ResetPassword />} />} />
|
||||
<Route path={Routes.ABOUT} element={<ContentFor element={<About />} />} />
|
||||
<Route path={Routes.USER_ROOT} element={<ContentFor element={<User />} />} />
|
||||
|
||||
<Route path={Routes.EMAIL_VERIFICATION} element={<ContentFor element={<EmailVerification />} />} />
|
||||
<Route path={Routes.RESET_PASSWORD_CONFIRMATION} element={<ContentFor element={<ResetPasswordConfirmation />} />} />
|
||||
|
|
|
@ -196,7 +196,8 @@ select:-webkit-autofill:focus {
|
|||
animation: wiggle 2s linear 1;
|
||||
}
|
||||
|
||||
.ant-table-row {
|
||||
.ant-table-row,
|
||||
.ant-list-item {
|
||||
&.unlisted {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
|
|
@ -126,6 +126,7 @@ const useDb = () => {
|
|||
const list = await tunesCollection.getList(page, perPage, {
|
||||
sort: '-updated',
|
||||
filter: `author = "${userId}"`,
|
||||
expand: 'author',
|
||||
});
|
||||
|
||||
return Promise.resolve({
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { Link } from 'react-router-dom';
|
||||
import {
|
||||
Button,
|
||||
Grid,
|
||||
|
@ -166,6 +167,11 @@ const Hub = () => {
|
|||
dataIndex: 'authorUsername',
|
||||
key: 'authorUsername',
|
||||
responsive: ['sm'],
|
||||
render: (userName: string, record: TunesRecordFull) => (
|
||||
<Link to={generatePath(Routes.USER_ROOT, { userId: record.author })}>
|
||||
{userName}
|
||||
</Link>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: 'Signature',
|
||||
|
@ -188,7 +194,7 @@ const Hub = () => {
|
|||
{
|
||||
dataIndex: 'tuneId',
|
||||
fixed: 'right',
|
||||
render: (tuneId: string, record) => {
|
||||
render: (tuneId: string, record: TunesRecordFull) => {
|
||||
const isOwner = currentUser?.id === record.author;
|
||||
const size = isOwner ? 'small' : 'middle';
|
||||
|
||||
|
|
|
@ -0,0 +1,113 @@
|
|||
import {
|
||||
useEffect,
|
||||
useState,
|
||||
} from 'react';
|
||||
import {
|
||||
generatePath,
|
||||
useMatch,
|
||||
useNavigate,
|
||||
} from 'react-router-dom';
|
||||
import {
|
||||
Button,
|
||||
Divider,
|
||||
List,
|
||||
Pagination,
|
||||
Typography,
|
||||
} from 'antd';
|
||||
import { ArrowRightOutlined } from '@ant-design/icons';
|
||||
import { Routes } from '../routes';
|
||||
import { formatTime } from '../utils/time';
|
||||
import useDb from '../hooks/useDb';
|
||||
import { aspirationMapper } from '../utils/tune/mappers';
|
||||
import {
|
||||
TunesRecordFull,
|
||||
UsersRecordFull,
|
||||
} from '../types/dbData';
|
||||
|
||||
const tunePath = (tuneId: string) => generatePath(Routes.TUNE_TUNE, { tuneId });
|
||||
|
||||
const Profile = () => {
|
||||
const navigate = useNavigate();
|
||||
const route = useMatch(Routes.USER_ROOT);
|
||||
const { getUserTunes } = useDb();
|
||||
const [page, setPage] = useState(1);
|
||||
const [pageSize, setPageSize] = useState(10);
|
||||
const [total, setTotal] = useState(0);
|
||||
const [isTunesLoading, setIsTunesLoading] = useState(false);
|
||||
const [tunesDataSource, setTunesDataSource] = useState<TunesRecordFull[]>([]);
|
||||
const [username, setUsername] = useState();
|
||||
|
||||
const loadData = async () => {
|
||||
setIsTunesLoading(true);
|
||||
try {
|
||||
const { items, totalItems } = await getUserTunes(route?.params.userId!, page, pageSize);
|
||||
setTotal(totalItems);
|
||||
setUsername((items[0].expand.author as UsersRecordFull).username);
|
||||
const mapped = items.map((tune) => ({
|
||||
...tune,
|
||||
key: tune.tuneId,
|
||||
year: tune.year,
|
||||
displacement: `${tune.displacement}l`,
|
||||
aspiration: aspirationMapper[tune.aspiration],
|
||||
published: formatTime(tune.updated),
|
||||
}));
|
||||
setTunesDataSource(mapped as any);
|
||||
} catch (error) {
|
||||
// request cancelled
|
||||
} finally {
|
||||
setIsTunesLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
loadData();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [page]);
|
||||
|
||||
return (
|
||||
<div className="small-container">
|
||||
<Divider>{username ? `${username}'s tunes` : 'No tunes yet'}</Divider>
|
||||
<List
|
||||
dataSource={tunesDataSource}
|
||||
loading={isTunesLoading}
|
||||
renderItem={(tune) => (
|
||||
<List.Item
|
||||
actions={[
|
||||
<Button icon={<ArrowRightOutlined />} onClick={() => navigate(tunePath(tune.tuneId))} />,
|
||||
]}
|
||||
className={tune.visibility}
|
||||
>
|
||||
<List.Item.Meta
|
||||
title={<>
|
||||
{tune.vehicleName} <Typography.Text code>{tune.signature}</Typography.Text>
|
||||
</>}
|
||||
description={<>
|
||||
{tune.engineMake}, {tune.engineCode}, {tune.displacement}, {tune.aspiration}
|
||||
</>}
|
||||
/>
|
||||
<div>
|
||||
<Typography.Text italic>{tune.published}</Typography.Text>
|
||||
</div>
|
||||
</List.Item>
|
||||
)}
|
||||
footer={
|
||||
<div style={{ textAlign: 'right' }}>
|
||||
<Pagination
|
||||
style={{ marginTop: 10 }}
|
||||
pageSize={pageSize}
|
||||
current={page}
|
||||
total={total}
|
||||
onChange={(newPage, newPageSize) => {
|
||||
setIsTunesLoading(true);
|
||||
setPage(newPage);
|
||||
setPageSize(newPageSize);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Profile;
|
|
@ -217,10 +217,7 @@ const Profile = () => {
|
|||
{tune.vehicleName} <Typography.Text code>{tune.signature}</Typography.Text>
|
||||
</>}
|
||||
description={<>
|
||||
{tune.engineMake},
|
||||
{tune.engineCode},
|
||||
{tune.displacement},
|
||||
{tune.aspiration}
|
||||
{tune.engineMake}, {tune.engineCode}, {tune.displacement}, {tune.aspiration}
|
||||
</>}
|
||||
/>
|
||||
<div>
|
||||
|
|
|
@ -26,6 +26,7 @@ export enum Routes {
|
|||
OAUTH_CALLBACK = '/auth/oauth-callback/:provider',
|
||||
|
||||
ABOUT = '/about',
|
||||
USER_ROOT = '/user/:userId',
|
||||
|
||||
REDIRECT_PAGE_OAUTH_CALLBACK = 'oauth',
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue