Skip to content
Snippets Groups Projects
Verified Commit e5f13be6 authored by Rafael László's avatar Rafael László :speech_balloon:
Browse files

Merge remote-tracking branch 'origin/add-news-page' into dev

# Conflicts:
#	package-lock.json
#	package.json
#	src/App.tsx
parents d1a1997f 4a5ef38d
No related branches found
No related tags found
1 merge request!19fix type imports
This diff is collapsed.
import { AxiosRequestConfig } from 'axios'; import { AxiosRequestConfig } from 'axios';
import { auth, AuthClient } from './auth'; import { auth, AuthClient } from './auth';
import { news, NewsClient } from './news';
const DEFAULT_BASE_URL = ''; const DEFAULT_BASE_URL = '';
...@@ -14,10 +15,12 @@ export function createClient( ...@@ -14,10 +15,12 @@ export function createClient(
}; };
const client = { const client = {
auth: auth(config), auth: auth(config),
news: news(config),
}; };
return client; return client;
} }
export type Client = { export type Client = {
auth: AuthClient; auth: AuthClient;
news: NewsClient;
}; };
import Axios, { AxiosRequestConfig } from 'axios';
import { INews } from '../types/News';
type NewsQuery = () => Promise<INews[]>;
type AddNewsMutation = (data: Partial<INews>) => Promise<INews>;
export type NewsClient = {
newsList: NewsQuery;
addNews: AddNewsMutation;
};
// TODO: Remove when auth flow complete
const authToken = process.env.AUTH_TOKEN;
export function news(config: AxiosRequestConfig): NewsClient {
const axios = Axios.create({
...config,
baseURL: `${config.baseURL}/api/v1/news`,
});
const newsList: NewsQuery = async (): Promise<INews[]> => {
const { data: response } = await axios.get<INews[]>('/', {
headers: { Authorization: `Bearer ${authToken}` },
});
return response;
};
const addNews: AddNewsMutation = async (data: Partial<INews>): Promise<INews> => {
const { data: response } = await axios.post<INews>('/', data, {
headers: { Authorization: `Bearer ${authToken}` },
});
return response;
};
return {
newsList,
addNews,
};
}
import {
Button,
Dialog,
DialogActions,
DialogContent,
DialogTitle,
Grid,
TextField,
} from '@material-ui/core';
import { Field, Form, Formik } from 'formik';
import React from 'react';
import { INews } from '../types/News';
interface AddNewsFormDialogProps {
open: boolean;
onClose: () => void;
onSubmit: (news: Partial<INews>) => void;
}
const AddNewsFormDialog: React.FC<AddNewsFormDialogProps> = ({ open, onClose, onSubmit }) => {
return (
<Dialog open={open} onClose={onClose}>
<Formik
initialValues={{
title: '',
text: '',
}}
onSubmit={(values): void => {
onSubmit(values);
}}
>
<Form>
<DialogTitle>Add News</DialogTitle>
<DialogContent>
<Grid container direction="column" spacing={2}>
<Grid item>
<Field label="Title" name="title" as={TextField} required />
</Grid>
<Grid item>
<Field label="Text" name="text" multiline as={TextField} required />
</Grid>
</Grid>
</DialogContent>
<DialogActions>
<Button onClick={onClose}>Cancel</Button>
<Button type="submit">Add</Button>
</DialogActions>
</Form>
</Formik>
</Dialog>
);
};
export default AddNewsFormDialog;
import { Grid, makeStyles, Typography } from '@material-ui/core'; import { Box, Grid, makeStyles, Typography } from '@material-ui/core';
import { parseISO } from 'date-fns';
import React from 'react'; import React from 'react';
import { formatDateTime } from '../util';
interface NewsProps { interface NewsProps {
title: string; title: string;
...@@ -11,32 +13,27 @@ interface NewsProps { ...@@ -11,32 +13,27 @@ interface NewsProps {
const useStyles = makeStyles((theme) => ({ const useStyles = makeStyles((theme) => ({
container: { container: {
color: 'white', color: 'white',
borderRadius: '8px',
backgroundColor: theme.palette.background.paper, backgroundColor: theme.palette.background.paper,
margin: theme.spacing(2), padding: theme.spacing(2),
padding: theme.spacing(1),
}, },
})); }));
const News: React.FC<NewsProps> = ({ title, content, author, createDate }) => { const News: React.FC<NewsProps> = ({ title, content, createDate }) => {
const classes = useStyles(); const classes = useStyles();
return ( return (
<Grid className={classes.container} container direction="column"> <Grid className={classes.container} container direction="column">
<Grid item> <Grid item>
<Typography variant="h6">{title}</Typography> <Typography variant="subtitle2" color="secondary">
{formatDateTime(parseISO(createDate))}
</Typography>
</Grid> </Grid>
<Grid item> <Grid item>
<Typography variant="body1">{content}</Typography> <Box marginY={2}>
<Typography variant="h4">{title}</Typography>
</Box>
</Grid> </Grid>
<Grid item container justify="flex-end">
<Grid item> <Grid item>
<Typography variant="subtitle2"> <Typography variant="body1">{content}</Typography>
<i>{author}</i>
</Typography>
<Typography variant="subtitle2">
<i>{createDate}</i>
</Typography>
</Grid>
</Grid> </Grid>
</Grid> </Grid>
); );
......
import { CircularProgress, Grid } from '@material-ui/core'; import { Box, Button, CircularProgress, Grid, Typography } from '@material-ui/core';
import React from 'react'; import React from 'react';
import useAddNews from '../hooks/useAddNews';
import useGetNews from '../hooks/useGetNews';
import { useToggle } from '../hooks/useToggle';
import { useUserContext } from '../hooks/useUserContext';
import { INews } from '../types/News';
import { Role } from '../types/Profile';
import AddNewsFormDialog from './AddNewsFormDialog';
import News from './News'; import News from './News';
interface Props {}
const NewsContainer: React.FC = () => { const NewsContainer: React.FC = () => {
const isLoading = false; const { isFetching, data } = useGetNews();
const { profile } = useUserContext();
const { mutateAsync: addNews, isError } = useAddNews();
const [open, { toggleOn, toggleOff }] = useToggle();
const handleAddNews = async (news: Partial<INews>): Promise<void> => {
await addNews(news);
if (!isError) {
toggleOff();
}
};
return isLoading ? ( return isFetching ? (
<CircularProgress /> <CircularProgress />
) : ( ) : (
<Grid container spacing={2}> <Box paddingY={2}>
<News title="ASd" author="Anonymus" content="ASDADDD" createDate="2021.01.01" /> <Grid container>
<Grid item xs={12} sm={3}>
<Box paddingX={2}>
<img
src="https://i.pinimg.com/474x/13/84/34/138434e6400eb73823192c74ea40bfc2.jpg"
height="auto"
width="80%"
alt="Fitness advertisement"
/>
</Box>
</Grid>
<Grid item xs={12} sm={6}>
<Grid container direction="column">
{data?.map((item) => (
<Grid item xs={12}>
<Box p={2}>
<News
title={item.title}
author={item.publishedBy}
content={item.text}
createDate={item.publishedAt}
/>
</Box>
</Grid>
))}
{profile && profile.role === Role.Admin && (
<Grid item container justify="center">
<Button variant="contained" color="secondary" onClick={toggleOn}>
Add news
</Button>
</Grid>
)}
</Grid>
</Grid>
<Grid container item xs={12} sm={3} justify="flex-end">
<Box paddingX={2}>
<Typography>Naptár (?)</Typography>
</Box>
</Grid>
</Grid> </Grid>
<AddNewsFormDialog open={open} onClose={toggleOff} onSubmit={handleAddNews} />
</Box>
); );
}; };
......
import { useMutation, UseMutationResult, useQueryClient } from 'react-query';
import { INews } from '../types/News';
import useClientContext from './useClientContext';
const useAddNews = (): UseMutationResult<INews, Error, Partial<INews>> => {
const { client } = useClientContext();
const queryClient = useQueryClient();
return useMutation<INews, Error, Partial<INews>>(
(data: Partial<INews>) => client.news.addNews(data),
{
onSuccess: () => {
queryClient.invalidateQueries('news');
},
},
);
};
export default useAddNews;
import { useQuery, UseQueryResult } from 'react-query';
import { INews } from '../types/News';
import useClientContext from './useClientContext';
const useGetNews = (): UseQueryResult<INews[], Error> => {
const { client } = useClientContext();
return useQuery<INews[], Error>('news', async () => client.news.newsList());
};
export default useGetNews;
import { Container } from '@material-ui/core';
import React from 'react'; import React from 'react';
import NewsContainer from '../components/NewsContainer'; import NewsContainer from '../components/NewsContainer';
import Page from './Page'; import Page from './Page';
const NewsPage: React.FC = () => ( const NewsPage: React.FC = () => (
<Page> <Page>
<Container>
<NewsContainer /> <NewsContainer />
</Container>
</Page> </Page>
); );
......
export interface INews { export interface INews {
title: string; title: string;
text: string; text: string;
publishedAt: Date; publishedAt: string;
publishedBy: string; publishedBy: string;
updatedBy?: string; updatedBy?: string;
} }
import { format } from 'date-fns';
const DATE_TIME_FORMAT = 'yyyy MMM dd H:mm';
// eslint-disable-next-line import/prefer-default-export
export const formatDateTime = (date: Date): string => {
return format(date, DATE_TIME_FORMAT);
};
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment