Skip to content

Commit

Permalink
Added search functionality and users can see their applications
Browse files Browse the repository at this point in the history
novaisea committed Jul 1, 2021
1 parent 25bb01b commit eba6fac
Showing 11 changed files with 206 additions and 48 deletions.
11 changes: 11 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@
"@testing-library/user-event": "^12.1.10",
"antd": "^4.7.3",
"axios": "^0.21.1",
"emailjs-com": "^3.1.0",
"jsdoc": "^3.6.7",
"react": "^17.0.1",
"react-dom": "^17.0.1",
1 change: 0 additions & 1 deletion src/App.js
Original file line number Diff line number Diff line change
@@ -19,7 +19,6 @@ import UserContext from './contexts/user';

const { Header, Content, Footer } = Layout;


/**
* @constructor App
* Makes requests to the backend to see if the user is logged in and also processes the logout
4 changes: 3 additions & 1 deletion src/components/account.js
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@ import React from 'react';
import UserContext from '../contexts/user';
import { Image } from 'antd'
import {useContext} from 'react';
import ApplicationGrid from './applicationgrid';

/**
* @function
@@ -44,10 +45,11 @@ function Account(props) {
return (
<>
<h1>Account</h1>
<Image width={200} alt="avatarURL" src={user.avatarURL} />
<Image width={200} src={user.avatarURL} />
<p>Username: {user.username} </p>
<p>Email: {user.email}</p>
{Object.keys(profile).map(key => <li key={key}>{key}: {profile[key]}</li>)}
<ApplicationGrid />
</>
);
}
24 changes: 1 addition & 23 deletions src/components/admin.js
Original file line number Diff line number Diff line change
@@ -4,8 +4,6 @@ import HomeGrid from './homegrid';
import { Image } from 'antd'
import Icon from './icon.png';

const { Search } = Input;

/**
* @function
* @name Admin
@@ -14,35 +12,15 @@ const { Search } = Input;
* @returns {object} Page Structure
*/
function Admin(props) {

const [search, setSearch] = useState(undefined);

/**
* @function
* @name searchHandler
* Function to handle the search query
* @param {object} value - Query for the search
* @returns {object} Output from the search
*/
function searchHandler(value) {
console.log("setting query")
setSearch(value)
}

return (
<div className="site-layout-content">
<div style={{ padding: '2% 20%' }}>
<Image width={200} alt="TLD" src={Icon} />
<PageHeader className="site-page-header"
title="Trading License Department"
subTitle="Admins can manage all applications from here."/>
<Search placeholder="Search Applications"
allowClear
enterButton="Search"
size="large"
onSearch={searchHandler}/>
</div>
<HomeGrid key={search} query={search}/>
<HomeGrid/>
</div>
);
}
68 changes: 68 additions & 0 deletions src/components/applicationgrid.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import React from 'react';
import { withRouter } from "react-router";
import { status, json } from '../utilities/requestHandlers';
import { Typography, Space, Button, List, Col, Row } from 'antd';
import UserContext from '../contexts/user';
import ApplicationItem from './applicationitem';

const { Title } = Typography;

class ApplicationGrid extends React.Component {

static contextType = UserContext;

constructor(props) {
super(props);
this.state = {
applications: []
}
}

componentDidMount() {
const id = this.context.user.ID;
const username = this.context.user.username
const password = this.context.user.password
fetch(`https://animal-hello-3000.codio-box.uk/api/v1/applications/account/${id}`, {
method: 'GET',
headers: {
"Authorization": "Basic " + btoa(username + ":" + password)
},
})
.then(status)
.then(json)
.then(application => {
this.setState({applications:application})
})
.catch(err => {
console.log(`Fetch error for application ${id}`)
});
};

render() {
if (!this.state.applications.length) {
if(!this.state.found){
return <h3>No applications found</h3>
} else {
return <h3>Loading applications...</h3>
}
}
const allApplications = this.state.applications.map(application => {
return (
<div style={{ padding: '2% 20%' }} key={application.ID}>
<List
className="demo-loadmore-list">
<ApplicationItem {...application} />
</List>
</div>
)
});

return(
<>
{allApplications}
</>
);
}
}

export default ApplicationGrid;
34 changes: 34 additions & 0 deletions src/components/applicationitem.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import React from 'react';
import { List } from 'antd';
import {Link} from "react-router-dom";

class ApplicationItem extends React.Component {

render() {

return(
<List.Item
actions={[<Link to={'/applications/' + this.props.ID}><a>View</a></Link>]}>
<List.Item.Meta
title={<h2>{this.props.companyName}</h2>}
description='Congratulations this application has been approved.'
/>
<div>{this.props.ID}, {this.props.userID}</div>
</List.Item>
);
return(
<List.Item
actions={[<Link to={'/applications/' + this.props.ID}><a>View</a></Link>]}>
<List.Item.Meta
title={<h2>{this.props.companyName}</h2>}
description='This application is pending approval.'
/>
<div>{this.props.dateCreated}</div>
</List.Item>
);
}


}

export default ApplicationItem;
3 changes: 0 additions & 3 deletions src/components/applicationsForUsers.js
Original file line number Diff line number Diff line change
@@ -5,9 +5,6 @@ import { status, json } from '../utilities/requestHandlers';

import UserContext from '../contexts/user';

window.$name = ""


const { Title, Paragraph } = Typography;

class ApplicationForUsers extends React.Component {
80 changes: 63 additions & 17 deletions src/components/homegrid.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { Col, Row } from 'antd';
import { Col, Row, Input } from 'antd';
import ApplicationCard from './applicationcard';
import { status, json } from '../utilities/requestHandlers';
import { withRouter } from 'react-router-dom';
@@ -13,7 +13,8 @@ class HomeGrid extends React.Component {
constructor(props) {
super(props);
this.state = {
applications: []
applications: [],
search:{}
}
}

@@ -44,8 +45,22 @@ class HomeGrid extends React.Component {
});
}

/** Renders the page using Application Card */
/**
* @function
* @name searchHandler
* Function to handle the search query
* @param {object} value - Query for the search
* @returns {object} Output from the search
*/
searchHandler = value => {
console.log(value)
this.setState({search:value})
}

/** Renders the page using Application Card and filters the search query */
render() {
const { Search } = Input;

if (!this.context.user.loggedIn) {
return (
<h2>Login first in order to see applications!</h2>
@@ -54,23 +69,54 @@ class HomeGrid extends React.Component {
return (
<h2>You have to be a user in order to see applications!</h2>
)
}else {
const applicationList = this.state.applications.map(application => {
}if(this.state.search.length){
const searchedApplication = this.state.applications.filter(application=>application.companyName.toLowerCase() === this.state.search.toLowerCase() || application.crn.toLowerCase() === this.state.search || application.email.toLowerCase() === this.state.search.toLowerCase()).map(application => {
return (
<div style={{padding:"10px"}} key={application.ID}>
<Col span={6}>
<ApplicationCard {...application} />
</Col>
</div>
)
});
return (
<div style={{ padding: '2% 20%' }}>
<Search placeholder="Search by Company Name, Company Reference Number or Email"
allowClear
enterButton="Search"
size="large"
onSearch={this.searchHandler}/>
<Row type="flex" justify="space-around">
{searchedApplication}
</Row>
</div>
);
}else{
const allApplications = this.state.applications.map(application => {
return (
<div style={{padding:"10px"}} key={application.ID}>
<Col span={6}>
<ApplicationCard {...application} />
</Col>
</div>
)
});
return (
<div style={{padding:"10px"}} key={application.ID}>
<Col span={6}>
<ApplicationCard {...application} />
</Col>
<div>
<div style={{ padding: '2% 20%' }}>
<Search placeholder="Search by Company Name, Company Reference Number or Email"
allowClear
enterButton="Search"
size="large"
onSearch={this.searchHandler}/>
</div>
<Row type="flex" justify="space-around">
{allApplications}
</Row>
</div>
)
});
return (
<Row type="flex" justify="space-around">
{applicationList}
</Row>
);
);
}
}
}
}

export default withRouter(HomeGrid);
1 change: 1 addition & 0 deletions src/components/nav.js
Original file line number Diff line number Diff line change
@@ -25,6 +25,7 @@ class Nav extends React.Component {
}if (this.context.user.role!="admin") {
return(
<Menu theme="dark" mode="horizontal" defaultSelectedKeys={['1']}>
<Menu.Item key="6" disabled={!this.context.user.loggedIn}><Link to="/">Home</Link></Menu.Item>
<Menu.Item key="1" disabled={this.context.user.role!= "user"}><Link to={`/myapplication/${this.context.user.ID}`}>My Application</Link></Menu.Item>
<Menu.Item key="2" disabled={this.context.user.role!= "user"}><Link to="/newapplication">Add Application</Link></Menu.Item>
<Menu.Item key="3" disabled={!this.context.user.loggedIn}><Link to="/account">Account</Link></Menu.Item>
27 changes: 24 additions & 3 deletions src/components/newApplication.js
Original file line number Diff line number Diff line change
@@ -3,13 +3,14 @@ import { status, json } from '../utilities/requestHandlers';
import { Form, Input, Button, Typography, DatePicker } from 'antd';
import UserContext from '../contexts/user';
import { Link } from "react-router-dom";
import emailjs from 'emailjs-com';

const { Title } = Typography;

const { TextArea } = Input

const nameRule=[
{required:true,message:'Please type the name of the compnay.',whitespace:false, min:5,max:150}
{required:true,message:'Please type the name of the compnay.',whitespace:false, min:3,max:150}
]
const crnRule=[
{required:true, message:'Please a valid company reference number.',whitespace:false, min:8,max:8}
@@ -44,10 +45,29 @@ class NewApplication extends React.Component {
constructor(props) {
super(props);
this.onFinish = this.onFinish.bind(this)
this.handleSubmit = this.handleSubmit.bind(this)
}

state = {redirect: null}

handleSubmit = (values) => { //Fix this to send the email!!
values.preventDefault(); // prevent reload

var formData = new FormData(this);
formData.append('gmail');
formData.append('template_tld');
formData.append('user_4pQL25dW7YNzoZmVCML9j');

fetch('https://api.emailjs.com/api/v1.0/email/send', {
method: 'POST',
body: JSON.stringify(formData)
}).then(data => {
alert('Your mail is sent!');
}).catch(err => {
alert('Oops... ' + JSON.stringify(err));
});
}

onFinish = (values) => {
const {confirm, ...data} = values;
fetch('https://animal-hello-3000.codio-box.uk/api/v1/applications', {
@@ -66,6 +86,7 @@ class NewApplication extends React.Component {
this.setState({redirect:`/myapplication/${this.context.user.id}`});
})
.catch(err => {
console.log(err)
alert("Error occurred, try again!")
})
}
@@ -83,12 +104,12 @@ class NewApplication extends React.Component {
}else {
return (

<Form {...formItemLayout} name="apply" onFinish={this.onFinish}>
<Form {...formItemLayout} name="apply" onFinish={this.onFinish} handleSubmit={this.handleSubmit}>

<h2>Application Form</h2>

<Form.Item name="companyName" label="Name of the Company" rules={nameRule}>
<TextArea showCount={true} maxLength={100}/>
<TextArea name="companyName" showCount={true} maxLength={100}/>
</Form.Item>

<Form.Item name="crn" label="Company Reference Number" rules={crnRule}>

0 comments on commit eba6fac

Please sign in to comment.