Changeset 13f1472 for frontend/src


Ignore:
Timestamp:
09/18/22 18:09:53 (22 months ago)
Author:
Danilo <danilo.najkov@…>
Branches:
master
Parents:
49b0bbd
Message:

vip functionallity + menu fields + alergens filtering + google/fb login + email queueing

Location:
frontend/src
Files:
1 added
6 edited

Legend:

Unmodified
Added
Removed
  • frontend/src/App.js

    r49b0bbd r13f1472  
    33import axios from 'axios'
    44import env from './env'
     5import { gapi } from 'gapi-script';
    56
    67import {Spin} from "antd";
     
    1819import Reset from "./Auth/Reset";
    1920import ToDo from "./Dashboard/ToDo";
     21import Vip from "./Dashboard/Vip";
    2022
    2123
     
    2628    getUser()
    2729  },[])
     30
     31  gapi.load('client:auth2', () => {
     32    gapi.client.init({
     33      clientId: '748923557453-ljii8ulhti93man769d2dd9soi7038j5.apps.googleusercontent.com',
     34      plugin_name: 'chat'
     35    });
     36  });
    2837
    2938  const getUser = () => {
     
    5059              <Route path="/dashboard/reviews" element={<Review/>}/>
    5160              <Route path="/dashboard/todo" element={<ToDo/>}/>
     61              <Route path="/dashboard/vip" element={<Vip/>}/>
    5262            </Route>
    5363            <Route path="/login" element={loading ? <Spin /> :  !user ? <Login setUser={setUser}/> :  <Navigate to="/dashboard" replace={true} />}/>
  • frontend/src/Auth/auth.js

    r49b0bbd r13f1472  
    66import '../App.css'
    77import env from "../env";
     8import { GoogleLogin } from 'react-google-login';
     9import FacebookLogin from 'react-facebook-login';
    810
    911const setAuthCookie = (token) => {
     
    2931            });
    3032            setLoading(false)
     33        })
     34    }
     35
     36    const googleLoginResponse = (response)=>{
     37        console.log(response)
     38        setLoading(true)
     39        console.log(response.tokenId)
     40        setAuthCookie('Bearer '+response.tokenId)
     41        axios.post(env.api+'Users/register',{email: response.profileObj.email, password:'', isConfirmed: true}).then(res => {
     42            setUser(res.data)
     43            setLoading(false)
     44            history(res.data.isAdmin ? '/dashboard' : '/')
     45        })
     46    }
     47
     48    const facebookLoginResponse = (response) =>{
     49        console.log(response)
     50        setLoading(true)
     51        setAuthCookie('Bearer '+response.accessToken)
     52        axios.post(env.api+'Users/register',{email: response.email, password:'', isConfirmed: true}).then(res => {
     53            setUser(res.data)
     54            setLoading(false)
     55            history(res.data.isAdmin ? '/dashboard' : '/')
    3156        })
    3257    }
     
    7398
    7499                        <Form.Item style={{margin:'0px'}}>
    75                             <Button type="primary" htmlType="submit" className="login-form-button" loading={loading}>
     100                            <Button type="primary" htmlType="submit" className="login-form-button" loading={loading} style={{marginBottom:'5px'}}>
    76101                                Log in
    77102                            </Button>
     103                            <br/>
     104                            <GoogleLogin
     105                                clientId="748923557453-ljii8ulhti93man769d2dd9soi7038j5.apps.googleusercontent.com"
     106                                buttonText="Логирај се со Google"
     107                                onSuccess={googleLoginResponse}
     108                            />
     109                            <FacebookLogin
     110                                appId="1455131645009417"
     111                                size={'small'}
     112                                textButton={'Логирај се со FB'}
     113                                icon="fa-facebook"
     114                                fields="name,email"
     115                                callback={facebookLoginResponse} />
    78116                            <div>
    79117                                Или <a href={"/register"}>регистрирај се!</a>
     
    102140        }
    103141        setLoading(true)
    104         axios.post(env.api+'Users/register',{email: attr.email, password: attr.password}).then(res => {
     142        axios.post(env.api+'Users/register',{email: attr.email, password: attr.password,isConfirmed:false}).then(res => {
    105143            setAuthCookie(res.data.token)
    106144            setUser(res.data)
     
    109147        })
    110148    }
     149
     150    const googleLoginResponse = (response)=>{
     151        console.log(response)
     152        setLoading(true)
     153        console.log(response.tokenId)
     154        setAuthCookie('Bearer '+response.tokenId)
     155        axios.post(env.api+'Users/register',{email: response.profileObj.email, password:'', isConfirmed: true}).then(res => {
     156            setUser(res.data)
     157            setLoading(false)
     158            history('/')
     159        })
     160    }
     161
     162    const facebookLoginResponse = (response) =>{
     163        console.log(response)
     164        setLoading(true)
     165        setAuthCookie('Bearer '+response.accessToken)
     166        axios.post(env.api+'Users/register',{email: response.email, password:'', isConfirmed: true}).then(res => {
     167            setUser(res.data)
     168            setLoading(false)
     169            history('/')
     170        })
     171    }
     172
     173
    111174    return(
    112175        <div style={{width:'100vw',height:'100vh', textAlign:'center', backgroundColor:'#F2F2F2'}}>
     
    165228
    166229                        <Form.Item style={{margin:'0px'}}>
    167                             <Button type="primary" htmlType="submit" className="login-form-button" loading={loading}>
     230                            <Button type="primary" htmlType="submit" className="login-form-button" loading={loading} style={{marginBottom:'5px'}}>
    168231                                Register
    169232                            </Button>
     233                            <br/>
     234                            <GoogleLogin
     235                                clientId="748923557453-ljii8ulhti93man769d2dd9soi7038j5.apps.googleusercontent.com"
     236                                buttonText="Регистрирај се со Google"
     237                                onSuccess={googleLoginResponse}
     238                            />
     239                            <div style={{margin:'5px'}}/>
     240                            <FacebookLogin
     241                                appId="1455131645009417"
     242                                size={'small'}
     243                                textButton={'Регистрирај се со FB'}
     244                                icon="fa-facebook"
     245                                fields="name,email"
     246                                callback={facebookLoginResponse} />
    170247                            <div>
    171248                                Или <a href={"/login"}>најави се!</a>
  • frontend/src/Dashboard.js

    r49b0bbd r13f1472  
    33import {Link, useNavigate} from "react-router-dom";
    44import {Outlet} from "react-router";
    5 import {BookOutlined, BulbOutlined, ContainerOutlined, QuestionCircleOutlined, UserOutlined} from "@ant-design/icons";
     5import {
     6    BookOutlined,
     7    BulbOutlined,
     8    ContainerOutlined,
     9    QuestionCircleOutlined, StarOutlined,
     10    UserOutlined
     11} from "@ant-design/icons";
    612import * as PropTypes from "prop-types";
    713import {Header} from "./Header";
     
    3036                        to="/dashboard/reviews">Оценки</Link></Menu.Item>
    3137                    <Menu.Item key="5" icon={<BookOutlined/>}><Link to="/dashboard/todo">ToDo</Link></Menu.Item>
     38                    <Menu.Item key="6" icon={<StarOutlined />}><Link to="/dashboard/vip">VIP</Link></Menu.Item>
    3239                </Menu>
    3340            </div>
  • frontend/src/Dashboard/Menu.js

    r49b0bbd r13f1472  
    11import React, {useEffect, useState} from 'react'
    2 import {Button, Form, Input, Card, notification} from "antd";
     2import {Button, Form, Input, Card, notification, Checkbox, message, Upload} from "antd";
    33import axios from "axios";
    44import env from "../env";
     5import {PlusOutlined} from "@ant-design/icons";
    56
    67const Menu = props => {
     
    2324    }
    2425
     26    const beforeUpload = (file) => {
     27        const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
     28        if (!isJpgOrPng) {
     29            message.error('Сликата мора да е формат jpg или png');
     30        }
     31        if(isJpgOrPng) setLoadingSave(true);
     32        return isJpgOrPng;
     33    }
     34    const uploadChanged = (ev) =>{
     35        if(ev.file.status == 'done'){
     36            getRestaurant()
     37        }
     38    }
     39
    2540    const addMenu = (data) => {
    2641        setLoadingSave(true);
     42        console.log(data)
    2743        axios.post(env.api + 'Menu/',{...data,price: parseInt(data.price)}, { headers: {Authorization: localStorage.getItem('Auth')}
    2844        }).then(res => {
     
    97113                    </Form.Item>
    98114                    <Form.Item
     115                        label="Алергени"
     116                        name="alergens"
     117                    >
     118                        <Input/>
     119                    </Form.Item>
     120                    <Form.Item
    99121                        label="Цена"
    100122                        name="price"
     
    109131                        <Input placeholder="Цена" type={'number'}/>
    110132                    </Form.Item>
     133                    <Form.Item
     134                        name="isVipOnly"
     135                        valuePropName="checked"
     136                    >
     137                        <Checkbox>Само за VIP</Checkbox>
     138                    </Form.Item>
    111139                    <Form.Item style={{textAlign: 'center'}}>
    112140                        <Button type="primary" htmlType="submit" loading={loadingSave}>
     
    118146            <div style={{textAlign:'start'}}>
    119147                {restaurant.menu.map(el =>
    120                     <Card title={el.title} extra={<p style={{color:'red',cursor:'pointer'}} onClick={()=>deleteMenu(el.id)}>Избриши</p>} style={{ width: 300, display:'inline-block', margin:'10px' }} size="small">
     148                    <Card key={el.id} title={el.title} extra={<div>{el.isVipOnly ? <span style={{color:'orange',fontWeight:'bold'}}>VIP </span>:''}<span style={{color:'red',cursor:'pointer'}} onClick={()=>deleteMenu(el.id)}>Избриши</span></div>} style={{ width: 300, display:'inline-block', margin:'10px' }} size="small">
     149                        <div style={{height:'100px', width:'270px'}}>
     150                            <Upload
     151                                name="file"
     152                                onChange={uploadChanged}
     153                                showUploadList={false}
     154                                beforeUpload={beforeUpload}
     155                                style={{height: '100px', overflow: 'hidden'}}
     156                                action={env.api+'Menu/'+el.id+'/upload'}
     157                            >
     158                                {el.image != "data:image/png;base64," ? <img style={{cursor: 'pointer'}} src={el.image} alt="avatar"
     159                                                                                           height='100px' width={'270px'}/> : <div style={{cursor:'pointer',margin: 15,border:'1px solid gray',padding: 5}}><PlusOutlined /><div style={{ marginTop: 8}}>Додади слика</div></div>}
     160                            </Upload>
     161                        </div>
    121162                        <p>{el.description}</p>
     163                        <p>Алергени: {el.alergens.length ==0 ? 'Нема' : el.alergens}</p>
    122164                        <b>{el.price} ден.</b>
    123165                    </Card>
  • frontend/src/FrontPage.js

    r49b0bbd r13f1472  
    22import {Header} from "./Header";
    33import {Link, useNavigate} from "react-router-dom";
    4 import {Button, Card, DatePicker, Form, Image, Input, Modal, notification, Rate, Spin} from "antd";
     4import {Button, Card, DatePicker, Form, Image, Input, Modal, notification, Rate, Spin, Upload} from "antd";
    55import placeholderImage from '../src/Assets/placeholder.png'
    66import AddNewReservation from "./Dashboard/AddNewReservation";
     
    88import env from "./env";
    99import Review from "./Dashboard/Review";
     10import {PlusOutlined} from "@ant-design/icons";
    1011
    1112const FrontPage = ({user, logout}) => {
     
    1718    const [refreshToggle, setRefreshToggle] = useState(false);
    1819    const history = useNavigate();
     20    const [filteredMenuItems, setFilteredMenuItems] = useState([]);
    1921
    2022    useEffect(()=>{
     
    2224        axios.get(env.api + 'Restaurants').then(res=>{
    2325            setRestaurant(res.data);
     26            console.log(user);
     27            if(!user || !user.isVip){
     28                setFilteredMenuItems(res.data.menu.filter(x => !x.isVipOnly));
     29            }else{
     30                setFilteredMenuItems(res.data.menu.sort((x,y) => x.isVipOnly ? -1 : 1));
     31            }
    2432            setLoading(false);
    2533        });
    26     },[])
     34    },[user])
    2735
    2836    useEffect(()=>{
     
    3341        }
    3442    },[user])
     43
     44    const updateSearchValue = (value) => {
     45        const val = value.target.value.toLowerCase();
     46        setFilteredMenuItems(items=>{
     47            if(val.length==0){
     48                return restaurant.menu;
     49            }
     50            const its = val.split(' ');
     51            let allItems = []
     52            if(!user || !user.isVip){
     53                allItems = [...restaurant.menu.filter(x => !x.isVipOnly)]
     54            }else{
     55                allItems = [...restaurant.menu.sort(x => x.isVipOnly)]
     56            }
     57            for(let it of its){
     58                if(it.length>0)
     59                    allItems = allItems.filter(x => !x.alergens.includes(it));
     60            }
     61            return allItems;
     62        })
     63    }
    3564
    3665    const saveNewReview = data =>{
     
    5382    return(
    5483        <div>
    55             <Header onClickButton={!user?()=>history('/login'):logout} buttonText={!user?'Најави се':'Одјави се'}/>
     84            <Header onClickButton={!user?()=>history('/login'):logout} buttonText={!user?'Најави се':'Одјави се'} isVip={user && user.isVip}/>
    5685            {loading ? <Spin style={{margin: 20}}/> :
    5786                <div style={{
     
    105134                        }} >
    106135                            <h2 style={{float: 'left'}}>Мени</h2>
     136                            <Input.Search onChange={updateSearchValue} placeholder={'Филтрирај алергени'} style={{float:'right', width:'200px'}}/>
    107137                        </div>
    108                         {restaurant.menu.map(el =>
    109                             <Card key={el.id} title={el.title} style={{ width: 280, display:'inline-block', margin:'10px' }} size="small">
     138                        {filteredMenuItems.map(el =>
     139                            <Card
     140                                key={el.id}
     141                                title={el.title}
     142                                extra={el.isVipOnly ? <span style={{color:'orange',fontWeight:'bold'}}>VIP </span>:''}
     143                                style={{ width: 280, display:'inline-block', margin:'10px',verticalAlign:'middle' }}
     144                                size="small"
     145                                cover={el.image != "data:image/png;base64," ? <img style={{cursor: 'pointer'}} src={el.image} alt="avatar"
     146                                                                                    height='100px' width={'270px'}/> : ''}
     147                            >
    110148                                <p>{el.description}</p>
     149                                <p>Алергени: {el.alergens.length ==0 ? 'Нема' : el.alergens}</p>
    111150                                <b>{el.price} ден.</b>
    112151                            </Card>
  • frontend/src/Header.js

    r49b0bbd r13f1472  
    1010            {props.buttonText}
    1111        </Button>
     12        {props.isVip ? <span style={{color:'orange', float:'right', fontSize:'28px', fontWeight:'bold', marginRight:'10px'}}>VIP</span>:''}
    1213    </div>;
    1314}
Note: See TracChangeset for help on using the changeset viewer.