Skip to content

Commit

Permalink
Merge pull request #70 from aic-factcheck/migrate_fe
Browse files Browse the repository at this point in the history
Migrate fe
  • Loading branch information
romanbutora committed Aug 9, 2023
2 parents 96f019d + c6ea6c8 commit eb9c35a
Show file tree
Hide file tree
Showing 19 changed files with 486 additions and 165 deletions.
8 changes: 8 additions & 0 deletions src/_state/reviewsLoaded.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { atom } from 'recoil';

const reviewsLoaded = atom({
key: 'reviewsLoaded',
default: false,
});

export default reviewsLoaded;
9 changes: 9 additions & 0 deletions src/_state/usersReviews.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { atom } from 'recoil';
import { IReview } from '../common/types';

const myReviews = atom({
key: 'myReviews',
default: [] as IReview[],
});

export default myReviews;
5 changes: 5 additions & 0 deletions src/api/reviews.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ export default class ReviewsService {
return factCheckBe.post<IReview>(`/articles/${articleid}/claims/${claimid}/reviews`, values, { headers });
};

static editreview = (articleId: string, claimId: string, reviewId: string, values: IReview) => {
const headers = { Authorization: `Bearer ${localStorage.getItem('accessToken')}` };
return factCheckBe.patch<IReview>(`/articles/${articleId}/claims/${claimId}/reviews/${reviewId}`, values, { headers });
};

static userReviews = (userid: string) => {
const headers = { Authorization: `Bearer ${localStorage.getItem('accessToken')}` };
return factCheckBe.get<IUserReview[]>(`/users/${userid}/reviews`, { headers });
Expand Down
5 changes: 2 additions & 3 deletions src/common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,15 @@ export interface IArticle {

export interface IReview {
_id: string,
claimId: {
_id: string
},
claim: IClaim,
text: string,
createdAt: string,
vote: string,
links: string[],
nPositiveVotes: number,
nNeutralVotes: number,
nNegativeVotes: number,
article: string,
author: {
_id: string,
firstName: string,
Expand Down
47 changes: 43 additions & 4 deletions src/components/AddReview/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ import { useNavigate } from 'react-router-dom';
import {
Button, Form, Input, Select, Row, Col, Typography, Divider,
} from 'antd';
import { useRecoilValue } from 'recoil';
import { useRecoilValue, useRecoilState } from 'recoil';
import { useTranslation } from 'react-i18next';
import { CloseOutlined } from '@ant-design/icons';
import authAtom from '../../_state/auth';
import { IClaim, IReview } from '../../common/types';
import reviewsService from '../../api/reviews.service';
import { NotificationContext } from '../NotificationContext/NotificationContext';
import myReviews from '../../_state/usersReviews';
import reviewsLoaded from '../../_state/reviewsLoaded';

const { Option } = Select;
const { Paragraph } = Typography;
Expand All @@ -33,6 +35,9 @@ const AddReview: React.FC<AddReviewProps> = ({ claim, closeModal, reviewsNum })
const [vote, setVote] = useState('TRUE');
const [linksList, setLinksList] = useState<string[]>([]);

const [myReviewsList, setMyReviewsList] = useRecoilState(myReviews);
const [loaded, setReviewsLoaded] = useRecoilState(reviewsLoaded);

useEffect(() => {
// redirect to home if already logged in
if (auth?.token === undefined) {
Expand All @@ -41,12 +46,21 @@ const AddReview: React.FC<AddReviewProps> = ({ claim, closeModal, reviewsNum })
const id = auth?.user._id;
const articleid = claim?.article._id;
const claimid = claim?._id;

if (id !== undefined) {
reviewsService.getReviews(articleid, claimid).then((res: any) => {
// const reviews = res.filter((el) => claimid === el?.claimId);
setReviewsList(res.data);
}).catch();
}

if (myReviewsList.length < 1 && loaded === false) {
reviewsService.userReviews(id).then((res: any) => {
// const claimsList = res.filter((el) => id === el?.author._id);
setMyReviewsList(res.data);
setReviewsLoaded(true);
}).catch();
}
}, [auth, navigate]);

const handleChange = (value: string) => {
Expand All @@ -66,6 +80,27 @@ const AddReview: React.FC<AddReviewProps> = ({ claim, closeModal, reviewsNum })
mergedValues.lang = 'cz';
mergedValues.links = linksList;

const newReview = {
author: {
_id: auth?.user?._id,
firstName: auth?.user.firstName,
lastName: auth?.user.lastName,
email: auth?.user.email,
level: auth?.user.level,
},
article: claim.article._id,
links: linksList,
createdAt: new Date().toString(),
// eslint-disable-next-line object-shorthand
text: values.text,
nNegativeVotes: 0,
nNeutralVotes: 0,
nPositiveVotes: 0,
_id: new Date().toString(),
claim,
vote,
} as IReview;

if (userId !== undefined) {
reviewsService.addreview(articleid, claimid, mergedValues).then((res: any) => {
const mergedReviews = [...reviewsList];
Expand All @@ -75,6 +110,12 @@ const AddReview: React.FC<AddReviewProps> = ({ claim, closeModal, reviewsNum })
mergedReviews.push(res.data);
claimForm.resetFields(['text']);
setReviewsList(mergedReviews);

// cache users reviews
newReview._id = res.data._id;
const mergedMyReviews = [...myReviewsList, newReview];
setMyReviewsList(mergedMyReviews);

notificationApi.info({
message: t('successfully_added_review'),
description: t('gained_30'),
Expand All @@ -84,10 +125,8 @@ const AddReview: React.FC<AddReviewProps> = ({ claim, closeModal, reviewsNum })
closeModal();
}).catch((err: any) => {
console.log(err);
const errorMessage = 'An error occurred while creating review.';
notificationApi.info({
message: errorMessage,
description: 'Review text and links must be at least 6 characters long',
message: err.response.data.message,
icon: <CloseOutlined />,
});
// closeModal();
Expand Down
168 changes: 168 additions & 0 deletions src/components/EditReview/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable max-len */
import React, { useState, useEffect, useContext } from 'react';
import { useNavigate } from 'react-router-dom';
import {
Button, Col, Divider, Form, Input, Row, Select, Typography,
} from 'antd';
import { useRecoilValue, useRecoilState } from 'recoil';
import { useTranslation } from 'react-i18next';
import { CheckOutlined, CloseOutlined } from '@ant-design/icons';
import myReviews from '../../_state/usersReviews';
import authAtom from '../../_state/auth';
import { IReview } from '../../common/types';
import reviewsService from '../../api/reviews.service';
import { NotificationContext } from '../NotificationContext/NotificationContext';

const { Paragraph } = Typography;
const { Title } = Typography;
const { Option } = Select;

interface Props {
review: IReview;
indexEdit: number;
}

const EditReview: React.FC<Props> = ({ review, indexEdit }) => {
const auth = useRecoilValue(authAtom);
const navigate = useNavigate();
const { t } = useTranslation();
const [, setVote] = useState(review.vote);
const [linksList, setLinksList] = useState<string[]>(review.links);
const [myReviewsList, setMyReviewsList] = useRecoilState(myReviews);
const notificationApi = useContext(NotificationContext);

useEffect(() => {
// redirect to home if already logged in
if (auth?.token === undefined) {
navigate('/sign-in');
}
}, [auth, navigate]);

const onFinish = (values: any) => {
console.log(values);
const mergedValues = values;
mergedValues.text = values.text;
mergedValues.vote = values.vote;
mergedValues.links = linksList;

console.log(mergedValues.text);
console.log(mergedValues.vote);
reviewsService.editreview(review.article, review.claim._id, review._id, mergedValues)
.then(() => {
notificationApi.info({
message: t('review_edited'),
icon: <CheckOutlined />,
});

// eslint-disable-next-line prefer-const
let reviewToEdit = { ...myReviewsList[indexEdit] } as IReview;
reviewToEdit.text = values.text;
reviewToEdit.links = values.links;
reviewToEdit.vote = values.vote;

// eslint-disable-next-line max-len
const mergedReviews = [...myReviewsList.slice(0, indexEdit), reviewToEdit, ...myReviewsList.slice(indexEdit + 1)];

setMyReviewsList(mergedReviews);
})
.catch((e) => {
console.log(e);
notificationApi.info({
message: e.response.data.message,
icon: <CloseOutlined />,
});
});
};

const handleChange = (value: string) => {
setVote(value);
console.log(value);
};

const handleChangeList = (value: string[]) => {
setLinksList(value);
console.log(value);
};

return (
<div>
<Row style={{
background: '#d86e3d', borderRadius: '10px', textAlign: 'center', padding: '1%', paddingTop: '2%',
}}
>
<Col span={24}>
<Paragraph style={{ color: 'white' }}>
{review?.claim?.text}
</Paragraph>
</Col>
</Row>
<Divider style={{ backgroundColor: 'white', width: '5%' }} />
<Title level={5} className="defaultForm" style={{ color: 'white', whiteSpace: 'pre-line', textDecoration: 'none' }}>My review :</Title>
<Form
name="basic"
labelCol={{ span: 24 }}
wrapperCol={{ span: 24 }}
// initialValues={{ remember: true }}
onFinish={onFinish}
// onFinishFailed={onFinishFailed}
autoComplete="off"
initialValues={{
text: review.text,
links: review.links,
vote: review.vote,
}}
>
<Form.Item
name="text"
label={t('review_text')}
style={{ color: '#000000' }}
rules={[{
required: true, min: 2,
},
]}
>
<Input.TextArea rows={3} id="reviewTextForm" />
</Form.Item>
<Form.Item
name="links"
label={t('review_links')}
style={{ color: '#000000' }}
rules={[{
required: true,
},
]}
>
<Select
id="reviewLinksForm"
mode="tags"
style={{ width: '100%' }}
placeholder="Tags Mode"
onChange={handleChangeList}
/>
</Form.Item>

<Form.Item
label={t('review_overall_trust')}
name="vote"
>
<Select defaultValue={review.vote} onChange={handleChange}>
<Option value="TRUE">{t('true')}</Option>
<Option value="PARTIALLY_TRUE">{t('partialy_true')}</Option>
<Option value="INCONCLUSIVE">{t('inconclusive')}</Option>
<Option value="NON_VERIFIABLE">{t('non_verifiable')}</Option>
<Option value="FALSE">{t('false')}</Option>
</Select>
</Form.Item>

<Form.Item wrapperCol={{ offset: 0, span: 22 }}>
<Button type="primary" htmlType="submit" id="reviewSubmitForm">
{t('edit')}
</Button>
</Form.Item>
</Form>
</div>
);
};

export default EditReview;
31 changes: 16 additions & 15 deletions src/components/MyArticles/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,21 +49,22 @@ const MyArticles: React.FC = () => {
}}
>
{
myArticlesList !== undefined ? (myArticlesList?.map((obj : IArticle, index: number) => (
<div key={obj?._id} style={{ margin: '1%', background: 'white', borderRadius: '10px' }}>
<Article
article={obj}
isEditable={allowEdit}
indexArticle={index}
/>
</div>
))) : (
<div className="emptyList">
{' '}
{t('no_articles_yet')}
{' '}
</div>
)
(myArticlesList !== undefined && myArticlesList.length > 0)
? (myArticlesList?.map((obj : IArticle, index: number) => (
<div key={obj?._id} style={{ margin: '1%', background: 'white', borderRadius: '10px' }}>
<Article
article={obj}
isEditable={allowEdit}
indexArticle={index}
/>
</div>
))) : (
<div className="emptyList">
{' '}
{t('no_articles_yet')}
{' '}
</div>
)
}
</List>
</Content>
Expand Down
27 changes: 14 additions & 13 deletions src/components/MyClaims/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,19 +48,20 @@ const MyClaims: React.FC = () => {
}}
>
{
myClaimsList !== undefined ? (myClaimsList?.map((obj: IClaim, index: number) => (
<div key={obj?._id} style={{ margin: '1%', background: 'white', borderRadius: '10px' }}>
<Claim
claim={obj}
index={index}
isEditable={allowEdit}
/>
</div>
))) : (
<div className="emptyList">
{t('no_claims_yet')}
</div>
)
(myClaimsList !== undefined && myClaimsList.length > 0)
? (myClaimsList?.map((obj: IClaim, index: number) => (
<div key={obj?._id} style={{ margin: '1%', background: 'white', borderRadius: '10px' }}>
<Claim
claim={obj}
index={index}
isEditable={allowEdit}
/>
</div>
))) : (
<div className="emptyList">
{t('no_claims_yet')}
</div>
)
}
</List>
</Content>
Expand Down
Loading

0 comments on commit eb9c35a

Please sign in to comment.