Skip to content

Commit

Permalink
feature: admin approval
Browse files Browse the repository at this point in the history
  • Loading branch information
goto-eof committed May 1, 2023
1 parent 6bfedb1 commit 0a476cf
Show file tree
Hide file tree
Showing 7 changed files with 129 additions and 28 deletions.
80 changes: 64 additions & 16 deletions src/Main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,28 @@ const myMenu = [
{ name: 'My Requests', url: '/myRequests' },
];

interface UserMenuItem {
label: string;
href: string;
}

const RIGHT_MENU: Map<string, Array<UserMenuItem>> = new Map([
[
'ADMIN',
[
{ label: 'User Offers', href: '/userOffers' },
{ label: 'User Requests', href: '/userRequests' },
],
],
[
'USER',
[
{ label: 'My Offers', href: '/myOffers' },
{ label: 'My Requests', href: '/myRequests' },
],
],
]);

export default function Main() {
const { isOpen, onOpen, onClose } = useDisclosure();
const [selectedMenu, setSelectedMenu] = useState('/');
Expand Down Expand Up @@ -158,22 +180,19 @@ export default function Main() {
</Box>
</MenuButton>
<MenuList>
<MenuItem
onClick={() => {
setSelectedMenu('');
navigate('/myOffers');
}}
>
My Offers
</MenuItem>
<MenuItem
onClick={() => {
setSelectedMenu('');
navigate('/myRequests');
}}
>
My Requests
</MenuItem>
{RIGHT_MENU.get(UserService.getRole())?.map((menuItem) => {
return (
<MenuItem
key={menuItem.href}
onClick={() => {
setSelectedMenu('');
navigate(menuItem.href);
}}
>
{menuItem.label}
</MenuItem>
);
})}
<MenuDivider />
<MenuItem
onClick={() =>
Expand Down Expand Up @@ -256,6 +275,10 @@ export default function Main() {
<Route path="/register" element={<Register />} />
<Route path="/authenticate" element={<Login />} />
<Route path="/view/:scope/:id" element={<ViewOfferRequest />} />
<Route
path="/view/:scope/:status/:id"
element={<ViewOfferRequest />}
/>

<Route
path="/myOffers"
Expand All @@ -279,6 +302,31 @@ export default function Main() {
/>
}
/>

<Route
path="/userOffers"
element={
<JobOffersRequests
key={'userOffers'}
type={JobConst.TYPE_OFFER}
scope={JobConst.SCOPE_PRIVATE}
status={JobConst.STATUS_CREATED}
title="User Offers"
/>
}
/>
<Route
path="/userRequests"
element={
<JobOffersRequests
key={'userRequests'}
type={JobConst.TYPE_REQUEST}
scope={JobConst.SCOPE_PRIVATE}
status={JobConst.STATUS_CREATED}
title="User Requests"
/>
}
/>
</Routes>
</Box>
</Box>
Expand Down
47 changes: 41 additions & 6 deletions src/components/job/JobOffersRequests.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,31 @@ import UserService from '../../service/UserService';
import Stars from './Stars';
import JobService from '../../service/JobService';
import Title from './Title';
import JobConst from '../../consts/JobConst';

interface Props {
type: number;
scope: string;
title: string;
status?: number;
}

export default function JobOffersRequests({ type, scope, title }: Props) {
const BASE_URL_RETRIEVE_ITEMS: string = `api/v1/job/${scope}/${type}`;
export default function JobOffersRequests({
type,
scope,
title,
status,
}: Props) {
console.log(status);
const BASE_URL_RETRIEVE_ITEMS: string =
status !== undefined
? `api/v1/job/${scope}/admin/${type}/${status}`
: `api/v1/job/${scope}/${type}`;
const BASE_URL_RETRIEVE_ITEMS_FIRST_PAGE: string = `${BASE_URL_RETRIEVE_ITEMS}/0`;
const BASE_URL_COUNT_ITEMS: string = `api/v1/job/${scope}/count/${type}`;
const BASE_URL_COUNT_ITEMS: string =
status !== undefined
? `api/v1/job/${scope}/admin/count/${type}/${status}`
: `api/v1/job/${scope}/count/${type}`;

const [offers, setOffers] = useState<Array<Job>>(new Array<Job>());
const [itemsCount, setItemsCount] = useState(0);
Expand Down Expand Up @@ -68,7 +82,7 @@ export default function JobOffersRequests({ type, scope, title }: Props) {
<SimpleGrid spacing={3}>
{offers &&
offers.map((item, idx) => (
<JobComponent scope={scope} key={idx} job={item} />
<JobComponent scope={scope} key={idx} job={item} status={status} />
))}
</SimpleGrid>
<Pagination
Expand All @@ -82,19 +96,30 @@ export default function JobOffersRequests({ type, scope, title }: Props) {
interface JobProps {
job: Job;
scope: string;
status?: number;
}

function JobComponent({ job, scope }: JobProps) {
function JobComponent({ job, scope, status }: JobProps) {
const [imageLoaded, setImageLoaded] = useState(false);
const navigate = useNavigate();
const goToViewOfferRequest = (id: number | undefined) => {
navigate(`/view/${scope}/${id}`);
navigate(
status !== undefined
? `/view/${scope}/${status}/${id}`
: `/view/${scope}/${id}`
);
};

function showUserButtons(job: Job) {
return UserService.isSameUsername(job.author?.username || '');
}

const approve = (job: Job): void => {
GenericService.post<Job>('api/v1/job/private/' + job.id).then((job) => {
navigate(job.type === JobConst.TYPE_OFFER ? '/offers' : '/requests');
});
};

return (
<>
<Card
Expand Down Expand Up @@ -174,6 +199,16 @@ function JobComponent({ job, scope }: JobProps) {
>
{JobService.calulateAcceptButtonLabel(job)}
</Button>
{UserService.isAdmin() && JobService.isCreated(job.status) && (
<Button
mr={3}
variant="solid"
colorScheme="blue"
onClick={() => approve(job)}
>
Approve
</Button>
)}
</Box>
</Box>
</Flex>
Expand Down
13 changes: 10 additions & 3 deletions src/components/job/ViewOfferRequest.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,24 @@ export default function ViewOfferRequest({}: Props) {
const { isOpen, onOpen, onClose } = useDisclosure();
const navigate = useNavigate();
const [modalImage, setModalImage] = useState<string>();
let { id, scope } = useParams();
let { id, scope, status } = useParams();
const scopeFromUrl = scope || 'public';

useEffect(() => {
GenericService.get<Job>(`api/v1/job/${scopeFromUrl}/${id}`).then((job) => {
GenericService.get<Job>(
status !== undefined
? `api/v1/job/${scopeFromUrl}/admin/${status}/${id}`
: `api/v1/job/${scopeFromUrl}/${id}`
).then((job) => {
setJob(job);
});
}, []);

const showUserButtons = (job: Job) => {
return UserService.isSameUsername(job.author?.username || '');
return (
scope === JobConst.SCOPE_PRIVATE &&
UserService.isSameUsername(job.author?.username || '')
);
};

const goToEditOfferRequest = (job: Job | undefined) => {
Expand Down
3 changes: 3 additions & 0 deletions src/consts/JobConst.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,7 @@ export default class JobConst {

static readonly SCOPE_PUBLIC = 'public';
static readonly SCOPE_PRIVATE = 'private';

static readonly STATUS_CREATED = 0;
static readonly STATUS_PUBLISHED = 1;
}
2 changes: 1 addition & 1 deletion src/service/GenericService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export default class GenericService {
});
}

public static async post<T>(modelName: string): Promise<Result<T>> {
public static async post<T>(modelName: string): Promise<T> {
return await customAxios
.post<T>(`${this.baseUrl}${modelName}`, '', { withCredentials: true })
.then(async (result: any) => {
Expand Down
6 changes: 5 additions & 1 deletion src/service/JobService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@ import JobConst from '../consts/JobConst';
import Job from '../dto/Job';

export default class JobService {
static isCreated(status: number | undefined) {
return status === JobConst.STATUS_CREATED;
}
public static calulateAcceptButtonLabel = (job: Job) => {
if (job.type === JobConst.TYPE_OFFER) {
return 'Request service';
}
if (job.type === JobConst.TYPE_REQUEST) {
return 'Provide service';
}
throw new Error('Function not implemented.');
return 'TEST';
// throw new Error('Function not implemented.');
};
}
6 changes: 5 additions & 1 deletion src/service/UserService.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import UserConst from '../consts/UserConst';
import UserProfile from '../dto/UserProfile';

export default class UserService {
static isAdmin(): boolean {
return UserService.getRole() === UserConst.ROLE_ADMIN;
}
public static getUser(): UserProfile {
return JSON.parse(localStorage.getItem('user') || '{}');
}

public static isSameUsername(username: string) {
public static isSameUsername(username: string): boolean {
return this.getUser().username === username;
}

Expand Down

0 comments on commit 0a476cf

Please sign in to comment.