diff --git a/src/appwrite.ts b/src/appwrite.ts index 8277eba..1d89323 100644 --- a/src/appwrite.ts +++ b/src/appwrite.ts @@ -2,6 +2,7 @@ import { Account, Client, Databases, + Functions, Storage, } from 'appwrite'; import { fetchEnv } from './utils/env'; @@ -15,10 +16,12 @@ client const account = new Account(client); const databases = new Databases(client); const storage = new Storage(client); +const functions = new Functions(client); export { client, account, databases, storage, + functions, }; diff --git a/src/hooks/useDb.ts b/src/hooks/useDb.ts index 44d0a5c..93873df 100644 --- a/src/hooks/useDb.ts +++ b/src/hooks/useDb.ts @@ -6,7 +6,10 @@ import { Query, Role, } from 'appwrite'; -import { databases } from '../appwrite'; +import { + databases, + functions, +} from '../appwrite'; import { TuneDbData, UsersBucket, @@ -131,6 +134,9 @@ const useDb = () => { getTune: (tuneId: string): Promise => getTune(tuneId), searchTunes: (search?: string): Promise> => searchTunes(search), getBucketId: (userId: string): Promise => getBucketId(userId), + // TODO: refactor those executions + getUser: (userId: string) => functions.createExecution('getUser', JSON.stringify({ userId })), + listUsers: (userIds: string[]) => functions.createExecution('listUsers', JSON.stringify({ userIds })), }; }; diff --git a/src/pages/Hub.tsx b/src/pages/Hub.tsx index 09cf210..1c9a287 100644 --- a/src/pages/Hub.tsx +++ b/src/pages/Hub.tsx @@ -12,6 +12,7 @@ import { CopyOutlined, StarOutlined, ArrowRightOutlined, + LoadingOutlined, } from '@ant-design/icons'; import { useCallback, @@ -37,13 +38,20 @@ import { const { useBreakpoint } = Grid; const { Text, Title } = Typography; +interface ListUsersResponse { + users: [{ + id: string; + name: string; + }]; +} + const tunePath = (tuneId: string) => generatePath(Routes.TUNE_TUNE, { tuneId }); const Hub = () => { const { xs } = useBreakpoint(); - const { searchTunes } = useDb(); + const { searchTunes, listUsers } = useDb(); const navigate = useNavigate(); - const [dataSource, setDataSource] = useState([]); + const [dataSource, setDataSource] = useState<{}[]>([]); // TODO: fix this type const [isLoading, setIsLoading] = useState(true); const searchRef = useRef(null); @@ -52,17 +60,26 @@ const Hub = () => { const list = await searchTunes(searchText); // TODO: create `unpublishedTunes` collection for this const filtered = list.documents.filter((tune) => !!tune.vehicleName); + + // set initial list setDataSource(filtered.map((tune) => ({ ...tune, key: tune.tuneId, year: tune.year, - author: 'John Doe', + author: , displacement: `${tune.displacement}l`, aspiration: aspirationMapper[tune.aspiration], publishedAt: new Date(tune.$updatedAt).toLocaleString(), stars: 0, }))); setIsLoading(false); + + // update list with users + const userList: ListUsersResponse = JSON.parse((await listUsers(filtered.map((tune) => tune.userId))).response); + setDataSource((prev) => prev.map((item: any) => ({ + ...item, + author: userList.users.find((el) => el.id === item.userId)?.name, + }))); }, 300); const debounceLoadData = useCallback((value: string) => loadData(value), [loadData]); @@ -80,7 +97,7 @@ const Hub = () => { <> {tune.vehicleName} - John Doe, {tune.publishedAt} + {tune.author}, {tune.publishedAt} {tune.engineMake}, {tune.engineCode}, {tune.displacement}, {tune.cylindersCount} cylinders, {tune.aspiration} {tune.signature} diff --git a/src/pages/Info.tsx b/src/pages/Info.tsx index 2b89616..cf2939a 100644 --- a/src/pages/Info.tsx +++ b/src/pages/Info.tsx @@ -1,3 +1,7 @@ +import { + useEffect, + useState, +} from 'react'; import { connect } from 'react-redux'; import ReactMarkdown from 'react-markdown'; import { @@ -21,6 +25,7 @@ import { import Loader from '../components/Loader'; import { Routes } from '../routes'; import { useAuth } from '../contexts/AuthContext'; +import useDb from '../hooks/useDb'; const { Item } = Form; const rowProps = { gutter: 10 }; @@ -30,14 +35,34 @@ const mapStateToProps = (state: AppState) => ({ tuneData: state.tuneData, }); +interface GetUserResponse { + id: string; + name: string; + tunes: []; +} + const Info = ({ tuneData }: { tuneData: TuneDataState }) => { const navigate = useNavigate(); const { currentUser } = useAuth(); + const { getUser } = useDb(); + const [author, setAuthor] = useState(); const goToEdit = () => navigate(generatePath(Routes.UPLOAD_WITH_TUNE_ID, { tuneId: tuneData.tuneId, })); + const loadData = async () => { + const authorData: GetUserResponse = JSON.parse((await getUser(tuneData.userId)).response); + setAuthor(authorData.name); + }; + + useEffect(() => { + if (tuneData?.userId) { + loadData(); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [tuneData]); + const canManage = tuneData?.userId === currentUser?.$id; const manageSection = ( @@ -66,6 +91,13 @@ const Info = ({ tuneData }: { tuneData: TuneDataState }) => {
Details
+ + + + + + +