Skip to content
This repository has been archived by the owner on Apr 14, 2024. It is now read-only.

Commit

Permalink
refactor: страница поиска и страница позиции (#71)
Browse files Browse the repository at this point in the history
  • Loading branch information
DieWerkself authored Nov 25, 2023
1 parent 7101cb5 commit d11db20
Show file tree
Hide file tree
Showing 27 changed files with 613 additions and 162 deletions.
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ module.exports = {
],
'react-hooks/exhaustive-deps': 'off',
'react/react-in-jsx-scope': 'off',

'jsx-a11y/accessible-emoji': 'off',
'react/prop-types': 'off',
'import/no-unresolved': 'error',
Expand Down
5 changes: 5 additions & 0 deletions src/app/providers/router/config.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
NotificationsPageDesktop,
} from '~/pages/notifications';
import { OnboardingPage } from '~/pages/onboarding';
import { PositionPage } from '~/pages/position';
import { ProfilePage, ProfilePageDesktop } from '~/pages/profile';
import {
AddProjectPage,
Expand Down Expand Up @@ -81,6 +82,10 @@ export const normalRoutes = [
path: PATHS.project,
view: { base: ProjectPage },
},
{
path: PATHS.position,
view: { base: PositionPage },
},
{
path: PATHS.addProject,
view: { base: AddProjectPage },
Expand Down
21 changes: 21 additions & 0 deletions src/entities/project/avatar/Avatar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { Image } from '@chakra-ui/react';

import { useApi } from '~/shared/hooks';

import placeholderAvatar from './placeholder-project-avatar.jpg';

interface AvatarProps {
projectId: string;
}

export const Avatar = ({ projectId }: AvatarProps) => {
const { projectsApi } = useApi();
return (
<Image
src={projectsApi.getProjectAvatar(projectId)}
fallbackSrc={placeholderAvatar}
height={32}
objectFit="cover"
/>
);
};
1 change: 1 addition & 0 deletions src/entities/project/avatar/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './Avatar';
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions src/entities/project/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ export * from './avatars-group';
export * from './api';
export * from './info';
export * from './filter';
export * from './position';
export * from './avatar';
72 changes: 72 additions & 0 deletions src/entities/project/position/PositionInfo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { Heading, Stack } from '@chakra-ui/layout';
import { Skeleton } from '@chakra-ui/react';
import { useQuery } from '@tanstack/react-query';

import { useApi } from '~/shared/hooks';
import { STag } from '~/shared/ui/STag';
import { Status } from '~/shared/ui/status';

import { Card } from '../card';

interface Project {
deadline: string | null;
status: string;
id: string;
name: string;
description: string | null;
owner_id: string;
startline: string;
created_at: string;
updated_at: string;
}

interface ProjectInfoProps {
spec: string;
skills: string[];
project: Project;
}

export const PositionInfo = ({ spec, skills, project }: ProjectInfoProps) => {
const { storageApi } = useApi();
const { data: allSkills, isSuccess: loadedSkills } = useQuery({
queryKey: ['skills'],
queryFn: () => storageApi.getSkills(),
staleTime: Infinity,
});

const { data: allSpecs, isSuccess: loadedSpecs } = useQuery({
queryKey: ['specs'],
queryFn: () => storageApi.getSpecs(),
});

const isLoaded = loadedSkills && loadedSpecs;

const mainTag = allSpecs?.data
.filter(({ id }) => id === spec)
.map(({ name }) => (name ? name : ''));

const tags = allSkills
?.filter(({ value }) => skills.includes(value))
.map(({ label }) => label);

return (
<>
<Stack gap={0} mb={3} alignItems="start">
<Status mb={3}>{project.status}</Status>
<Card
title={project.name}
date={project.startline}
description={project.description}
fullDescription={true}
/>
</Stack>

<Stack gap={0} mb={6}>
<Heading variant="h2">В проект требуется</Heading>
<Skeleton isLoaded={isLoaded} borderRadius="2xl" fadeDuration={2}>
<STag mainTags={mainTag} tags={tags} />
</Skeleton>
</Stack>
</>
);
};
1 change: 1 addition & 0 deletions src/entities/project/position/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './PositionInfo';
113 changes: 113 additions & 0 deletions src/pages/position/Position.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import {
Container,
Flex,
Heading,
Button,
Card as ChakraCard,
CardBody,
Skeleton,
Portal,
} from '@chakra-ui/react';
import { useQuery } from '@tanstack/react-query';

import { Avatar, Contacts, PositionInfo } from '~/entities/project';

import { useApi, useAuth, useIsMobile, useLayoutRefs } from '~/shared/hooks';
import { GoBack } from '~/shared/ui/GoBack';

interface ProjectBase {
positionId: string;
}

export const Position = ({ positionId }: ProjectBase) => {
const layout = useLayoutRefs();
const { userId, isAuth } = useAuth();
const { projectsApi, userApi } = useApi();
const isMobile = useIsMobile();

const { data: position, isSuccess: loadedPosition } = useQuery({
queryKey: ['getPosition', positionId],
queryFn: () => projectsApi.getPosition(positionId),
staleTime: Infinity,
});

const userIsOwner = isAuth && loadedPosition && userId !== position.project.owner_id;

return (
<Container maxW="md" display="flex" flexDirection="column">
<Flex
position="sticky"
bg="bg"
zIndex={3}
top={0}
alignItems="center"
justifyContent="space-between"
py={4}
>
<Flex alignItems="center">
<GoBack />
<Heading variant="h2" mb={0}>
Проект
</Heading>
</Flex>
</Flex>
{!loadedPosition ? (
<Skeleton
isLoaded={loadedPosition}
borderRadius="2xl"
fadeDuration={2}
height="550px"
/>
) : (
<ChakraCard
bg="white"
borderRadius="2xl"
overflow="hidden"
boxShadow="none"
alignContent="center"
>
<Avatar projectId={position.project.id} />
<CardBody padding={isMobile ? 5 : 6}>
<PositionInfo
spec={position.specialization_id}
skills={position.skills}
project={position.project}
/>
<Contacts ownerId={position.project.owner_id} />
</CardBody>
</ChakraCard>
)}
{layout?.footer && (
<Portal containerRef={layout.footer}>
<Container py={2} maxW="md">
{userIsOwner && (
<Button
type="button"
onClick={() => {
// handleTabsChange(1);
}}
fontSize="sm"
fontWeight="600"
w="full"
>
Откликнуться
</Button>
)}
{!isAuth && (
<Button
type="button"
as="a"
href={userApi.authURL}
fontSize="sm"
fontWeight="600"
w="full"
>
Зарегистрироваться
</Button>
)}
</Container>
</Portal>
)}
</Container>
);
};
15 changes: 15 additions & 0 deletions src/pages/position/PositionPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Navigate, useParams } from 'react-router-dom';

import { PATHS } from '~/shared/lib/router';

import { Position } from './Position';

export const PositionPage = () => {
const { id: positionId } = useParams();

return !positionId ? (
<Navigate to={PATHS.notFound} replace />
) : (
<Position positionId={positionId} />
);
};
2 changes: 2 additions & 0 deletions src/pages/position/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './Position';
export * from './PositionPage';
13 changes: 13 additions & 0 deletions src/pages/projects/api/useGetAllProjects.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { QueryFunctionContext, QueryKey, useInfiniteQuery } from '@tanstack/react-query';

import { api } from '~/shared/contexts';

export const useGetAllProjects = (userId: string) =>
useInfiniteQuery({
queryKey: ['getAllProjects', userId],
queryFn: ({ pageParam = 1 }: QueryFunctionContext<QueryKey, number>) =>
api.projectsApi.getAllProjects({ page: pageParam, owner_id: userId }),
getNextPageParam: (lastPage) =>
lastPage.page < lastPage.total_pages ? lastPage.page + 1 : undefined,
staleTime: 5000,
});
19 changes: 2 additions & 17 deletions src/pages/projects/ui/ProjectBase.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,17 @@ import {
Button,
Card as ChakraCard,
CardBody,
Image,
Skeleton,
Portal,
} from '@chakra-ui/react';
import { useEffect, useState } from 'react';

import {
Avatar,
Contacts,
ProjectInfo,
useGetPositions,
useGetProject,
useGetProjectAvatar,
} from '~/entities/project';
import { useGetSkills, useGetSpecs } from '~/entities/storage';

Expand All @@ -31,15 +30,12 @@ export const ProjectBase = ({ projectId }: ProjectBase) => {
const layout = useLayoutRefs();
const { userId } = useAuth();
const isMobile = useIsMobile();
const [projectAvatarImg, setProjectAvatarImg] = useState<string>('');
const [specsIds, setSpecsIds] = useState<string[]>([]);
const [unvaluedSkillsIds, setUnvaluedSkillsIds] = useState<string[][]>([]);
const [readySkillsIds, setReadySkillsIds] = useState<string[][]>([]);

const { data: specs, isSuccess: loadedSpecs } = useGetSpecs();
const { data: project, isSuccess: loadedProject } = useGetProject(projectId);
const { data: projectAvatar, isSuccess: loadedProjectAvatar } =
useGetProjectAvatar(projectId);
const { data: projectPositions, isSuccess: loadedProjectPositions } =
useGetPositions(projectId);

Expand All @@ -48,12 +44,6 @@ export const ProjectBase = ({ projectId }: ProjectBase) => {
const positionSkillsValue = useGetSkills(unvaluedSkillsIds);
const loadedPositionSkillsValue = positionSkillsValue.every((query) => query.isSuccess);

useEffect(() => {
if (loadedProjectAvatar) {
setProjectAvatarImg(URL.createObjectURL(projectAvatar));
}
}, [loadedProjectAvatar]);

useEffect(() => {
if (projectPositions?.data.length) {
const idsSpecPositions = projectPositions.data.map(
Expand Down Expand Up @@ -114,12 +104,7 @@ export const ProjectBase = ({ projectId }: ProjectBase) => {
boxShadow="none"
alignContent="center"
>
<Image
src={projectAvatarImg}
fallbackSrc="https://img.freepik.com/premium-photo/programmer-working-computer-office_229060-14.jpg"
height={32}
objectFit="cover"
/>
<Avatar projectId={projectId} />
<CardBody padding={isMobile ? 5 : 6}>
<ProjectInfo
allSpecs={specs?.data}
Expand Down
Loading

0 comments on commit d11db20

Please sign in to comment.