Sorry to see you go...{alert("You successfully signed out")}{window.location = "/"}
;
12 | }
13 | }
14 |
15 | export default connect(null, actions)(Signout);
16 |
--------------------------------------------------------------------------------
/python/save.py:
--------------------------------------------------------------------------------
1 | import cv2
2 | import os
3 |
4 | def make_directory(path):
5 | '''
6 | This function is to make directory for pictures.
7 | It checks whether a directory exists or not befor saving a picture.
8 | If it exists, just pass. If not, it makes the directory.
9 | '''
10 | if not os.path.exists(path):
11 | os.makedirs(path)
12 |
13 | def save_photo(file_path, frame):
14 | '''
15 | This function is to save photos.
16 | After making directory, it save a picture and returns path of the picture.
17 | '''
18 | cv2.imwrite(file_path, frame)
19 |
--------------------------------------------------------------------------------
/frontend/src/components/tab.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | class Tab extends Component {
4 | handleClick = (e) => {
5 | e.preventDefault();
6 | this.props.handleClick();
7 | }
8 |
9 | render(){
10 | return (
11 |
The unique mechanism of our SmartBell (to trigger the lock you simply face the door while pressing the doorbell button) is nearly as fast as using a key but far more convenient.
31 | Granting access to the building depending on whether a person has been granted rights to enter makes it the best method for everyday use.
32 |
33 |
34 |
Sign in
35 |
47 |
48 |
49 |
50 |
51 | );
52 | }
53 | }
54 |
55 | function mapStateToProps(state) {
56 | return { errorMessage: state.bell.error };
57 | }
58 |
59 | export default reduxForm({
60 | form: 'signin',
61 | fields: ['email', 'password']
62 | }, mapStateToProps, actions)(Signin);
63 |
--------------------------------------------------------------------------------
/frontend/style/style.css:
--------------------------------------------------------------------------------
1 | .divisionLine {
2 | clear: both;
3 | }
4 | .error {
5 | color: red;
6 | }
7 |
8 | .nopadding{
9 | margin: 0;
10 | padding: 0;
11 | line-height: 2 !important;
12 | }
13 |
14 | /*Custom CSS*/
15 | .wrapper{
16 | display: table;
17 | }
18 |
19 | .content-wrapper {
20 | height: 100vh;
21 | width: 100vw;
22 | display: table-cell;
23 | }
24 |
25 | .btn-custom {
26 | background-color: transparent !important;
27 | }
28 |
29 | .bg-signin {
30 | background-image: url('./static/images/bg.jpg');
31 | background-size: cover;
32 | }
33 |
34 | .bg-main {
35 | background-image: url('./static/images/bg-main.png');
36 | background-size: cover;
37 | }
38 |
39 | .visitor-line{
40 | line-height: 3.0 !important;
41 | }
42 |
43 |
44 | .list-group-item{
45 | font-size: 15px;
46 | background: transparent !important;
47 | }
48 |
49 | .navbar-slim{
50 | margin-bottom: 0px !important;
51 | }
52 |
53 | .navbar-custom{
54 | margin-bottom: 0px !important;
55 | font-size: 18px;
56 | background: black;
57 | }
58 |
59 | nav li {
60 | display: inline-block;
61 | margin-right: 5px;
62 | }
63 | nav li a {
64 | display: inline-block;
65 | padding: 8px 10px;
66 | color: #8c8caf;
67 | text-decoration: none;
68 | }
69 | nav li a:hover {
70 | color: #fff;
71 | background: #68686d;
72 | text-decoration: none;
73 | }
74 | nav li.current a {
75 | color: #fff;
76 | background: #b3b2ba;
77 | text-decoration: none;
78 | }
79 |
80 | .nav-link {
81 | font-size: 19px !important;
82 | }
83 |
84 | a {
85 | text-decoration: none;
86 | }
87 |
88 | .thumbnail img {
89 | width: 100%;
90 | height: auto;
91 | max-height: 100%;
92 | }
93 | .displayNone {
94 | display: none;
95 | }
96 | .fadeIn{
97 | color:white;
98 | -webkit-animation: fadein 0.7s; /* Safari, Chrome and Opera > 12.1 */
99 | -moz-animation: fadein 0.7s; /* Firefox < 16 */
100 | -ms-animation: fadein 0.7s; /* Internet Explorer */
101 | -o-animation: fadein 0.7s; /* Opera < 12.1 */
102 | animation: fadein 0.7s;
103 | }
104 |
105 | @keyframes fadein {
106 | from { opacity: 0; }
107 | to { opacity: 1; }
108 | }
109 |
110 | /* Firefox < 16 */
111 | @-moz-keyframes fadein {
112 | from { opacity: 0; }
113 | to { opacity: 1; }
114 | }
115 |
116 | /* Safari, Chrome and Opera > 12.1 */
117 | @-webkit-keyframes fadein {
118 | from { opacity: 0; }
119 | to { opacity: 1; }
120 | }
121 |
122 | /* Internet Explorer */
123 | @-ms-keyframes fadein {
124 | from { opacity: 0; }
125 | to { opacity: 1; }
126 | }
127 |
128 | /* Opera < 12.1 */
129 | @-o-keyframes fadein {
130 | from { opacity: 0; }
131 | to { opacity: 1; }
132 | }
133 | .fadeOut{
134 | -webkit-animation: fadeout 0.7s; /* Safari, Chrome and Opera > 12.1 */
135 | -moz-animation: fadeout 0.7s; /* Firefox < 16 */
136 | -ms-animation: fadeout 0.7s; /* Internet Explorer */
137 | -o-animation: fadeout 0.7s; /* Opera < 12.1 */
138 | animation: fadeout 0.7s;
139 | }
140 |
141 | @keyframes fadeout {
142 | from { opacity: 1; }
143 | to { opacity: 0; }
144 | }
145 |
146 | /* Firefox < 16 */
147 | @-moz-keyframes fadeout {
148 | from { opacity: 1; }
149 | to { opacity: 0; }
150 | }
151 |
152 | /* Safari, Chrome and Opera > 12.1 */
153 | @-webkit-keyframes fadeout {
154 | from { opacity: 1; }
155 | to { opacity: 0; }
156 | }
157 |
158 | /* Internet Explorer */
159 | @-ms-keyframes fadeout {
160 | from { opacity: 1; }
161 | to { opacity: 0; }
162 | }
163 |
164 | /* Opera < 12.1 */
165 | @-o-keyframes fadeout {
166 | from { opacity: 1; }
167 | to { opacity: 0; }
168 | }
169 |
170 | .pagination a:hover {
171 | cursor: pointer;
172 | }
173 |
--------------------------------------------------------------------------------
/python/collect.py:
--------------------------------------------------------------------------------
1 | import cv2
2 | import numpy as np
3 | import face_recognition
4 | import dlib
5 | import pickle
6 | import os
7 | import save
8 | from pymongo import MongoClient
9 |
10 | mongo_db = MongoClient('localhost',27017)
11 | db = mongo_db.smartbell.visitors
12 |
13 | def encoding_picture(picture_path, __id):
14 | '''
15 | This function is to collect encoding face features.
16 | The photo is encoded and saved with associated visitor's id.
17 | If it's first time to dump, just dump it.
18 | Otherwise, load 'faces_encodings.txt', append it to registered data, then dump.
19 | '''
20 | try:
21 | print("encoding")
22 | image = face_recognition.load_image_file(picture_path)
23 | small_image = cv2.resize(image, (0, 0), fx=0.25, fy=0.25)
24 | # Encode the visitor's face
25 | image_face_encoding = face_recognition.face_encodings(small_image)[0]
26 | # Associate visitor's id and encoding data of visitor's face
27 | data = [[__id],image_face_encoding]
28 |
29 | # Save the associated data
30 | # If it's first time, just dump
31 | if os.path.getsize('faces_encodings.txt') == 0:
32 | with open('faces_encodings.txt','wb') as f:
33 | pickle.dump(data,f)
34 | else:
35 | # Load the registered data
36 | with open('faces_encodings.txt','rb') as f:
37 | known_faces_encoding_data = pickle.load(f)
38 | # Append [[visitor's id],[the encoding data of visitor's face]] to the registered data
39 | known_faces_encoding_data = np.vstack((known_faces_encoding_data,data))
40 | # Then, dump
41 | with open('faces_encodings.txt','wb') as f:
42 | pickle.dump(known_faces_encoding_data, f)
43 | return "success"
44 |
45 | except EOFError:
46 | return "fail"
47 |
48 | def upload_photo():
49 | '''
50 | This function is one of ways for collecting face features and is executed When administrator uploads the new visitor' photo.
51 | It saves the photo to static path which is 'pics/upload'.
52 | '''
53 | print("upload photo func")
54 | save.make_directory('pics/upload')
55 | visitors = db.find_one(sort=[('_id',-1)])
56 |
57 | return encoding_picture('pics/upload/img0.jpg', visitors['_id'])
58 |
59 | def cancel_add():
60 | '''
61 | This function is executed when administrator cancles to add a visitor.
62 | It finds last person in database and deletes it.
63 | '''
64 | print("cancel add visitor")
65 | visitors = db.find_one(sort=[('_id',-1)])
66 | db.remove({'_id':visitors['_id']})
67 | print("cancel success")
68 |
69 | def make_photo(frame):
70 | '''
71 | This function is one of ways for collecting face features and is exctued when administrator makes photo.
72 | It checks whether the photo is enough to encode or not.
73 | If the photo is enough, it saves the photo to static path which is 'pics/img0.jpg' and calls encoding_picture function.
74 | If you don't save the photo as .jpg format and immediately save the photo from usb camera, encoding face features should be different and incorrect.
75 | So, the photo has to be saved as .jpg format before excuting encoding function.
76 | Otherwise, it returns fail.
77 | '''
78 | save.make_directory('pics')
79 | visitors = db.find_one(sort=[('_id',-1)])
80 |
81 | # It affects dlib speed. If frame size is small, dlib would be faster than normal size frame
82 | small_frame = cv2.resize(frame, (0, 0), fx=0.25, fy=0.25)
83 | # Detect face in the frame
84 | face_locations = face_recognition.face_locations(small_frame)
85 |
86 | # If not detect face
87 | if len(face_locations) == 0:
88 | print("face detection fails")
89 | return "fail"
90 |
91 | else:
92 | path = 'pics/img0.jpg'
93 | # Save the visitor's face as '.jpg'
94 | save.save_photo(path, frame)
95 | result = encoding_picture(path, visitors['_id'])
96 |
97 | if result == "success":
98 | print("Success to register")
99 | else:
100 | print("Chcek picture path")
101 |
102 | return result
103 |
--------------------------------------------------------------------------------
/frontend/src/components/auth/signup.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { reduxForm } from 'redux-form';
3 | import * as actions from '../../actions';
4 |
5 | class Signup extends Component {
6 | handleFormSubmit(formProps) {
7 | // Call action creator to sign up the user!
8 | this.props.signupUser(formProps);
9 | }
10 |
11 | renderAlert() {
12 | if (this.props.errorMessage) {
13 | return (
14 |
The unique mechanism of our SmartBell (to trigger the lock you simply face the door while pressing the doorbell button) is nearly as fast as using a key but far more convenient.
30 | Granting access to the building depending on whether a person has been granted rights to enter makes it the best method for everyday use.
31 |
32 |
33 |
Create account
34 |
53 |
54 |
55 |
56 |
57 | );
58 | }
59 | }
60 |
61 | function validate(formProps) {
62 | const errors = {};
63 |
64 | if (!formProps.email) {
65 | errors.email = 'Please enter an email';
66 | }
67 |
68 | if (!formProps.password) {
69 | errors.password = 'Please enter a password';
70 | }
71 |
72 | if (!formProps.passwordConfirm) {
73 | errors.passwordConfirm = 'Please enter a password confirmation';
74 | }
75 |
76 | if (formProps.password !== formProps.passwordConfirm) {
77 | errors.password = 'Passwords must match';
78 | }
79 |
80 | return errors;
81 | }
82 |
83 | function mapStateToProps(state) {
84 | return { errorMessage: state.bell.error };
85 | }
86 |
87 | export default reduxForm({
88 | form: 'signup',
89 | fields: ['email', 'password', 'passwordConfirm'],
90 | validate
91 | }, mapStateToProps, actions)(Signup);
92 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Face recognition security system
2 |
3 | - Video demonstration of working application is available on the following link: https://youtu.be/qb1KZ4enTIA
4 |
5 | The main goal of creating such a system is to make security as convenient as possible. Granting access to various facilities and areas inside them without keys, cards, or passwords can make the presence of a security guard or continuous in-person monitoring obsolete. At the same time, it can eliminate inconvenience caused by carrying keys and paper ID.
6 |
7 | Smart security is the future, and with the help of the technology available today, an affordable intelligent security system is within our reach. This application is a low-cost, adaptive, and extensible surveillance system focused on identifying visitors. It can be integrated into an existing alarm system or be paired with a lock. It operates in real time and can distinguish between someone who is in the face database and someone who is not (a potential intruder).
8 |
9 | ## System architecture
10 |
11 | 
12 |
13 | ## Application logic
14 |
15 | The system relies on a facial recognition technique and does it in real time. User simply walk up to the door that he/she wants to open or the room he/she wants to enter and presses the button: the system will either recognize user as a trusted visitor and let the user in, or it will identify user as a stranger and deny access.
16 |
17 | The system, for the most part, is looking for faces. To get clearance, each user needs a profile picture that the algorithm can analyze for unique features. Then, whenever the same user is trying to get into a building or area, the system steps in. If it recognizes that face, the LED blinks once and that person is cleared for entry or twice if access for this person is forbidden or no match is found within visitors’ database.
18 |
19 | The core of the application is face recognition algorithm which first detects a face, then encodes face features and save them in a text file to be later compared alongside with another visitors’ face features to any new person trying to access a building or a room.
20 |
21 | 
22 |
23 | ## Application features
24 |
25 | - Face recognition
26 | - Managing visitors
27 | - add/delete visitor
28 | - change the access right for visitor
29 | - add visitor's photo from camera or from local storage
30 | - History of entered visitors
31 | - Authentication for administrator
32 | - Video stream to web application
33 | - Email notifications of entering the place
34 | - Blocking the door via email link in case of cheating
35 |
36 | 
37 |
38 | ## System installation
39 |
40 | - Software requirements
41 | - Download the code from GitHub repository
42 | $ git clone https://github.com/dmitrykhramov/Smart-Bell.git
43 |
44 | - Install MongoDB
45 | Available for download from https://www.mongodb.com/.
46 |
47 | - Install Python libraries
48 | $ pip install -r requirements.txt
49 |
50 | - Install OpenCV
51 |
52 | Version 2.4.9.1 is available for download from: https://github.com/opencv/opencv.
53 |
54 | Guidelines for Raspberry Pi installation: https://www.pyimagesearch.com/2016/04/18/install-guide-raspberry-pi-3-raspbian-jessie-opencv-3/
55 |
56 | - Install DLIB library
57 |
58 | Guidelines for Raspberry Pi installation: https://www.pyimagesearch.com/2017/05/01/install-dlib-raspberry-pi/
59 |
60 | - Hardware requirements
61 | - RaspberryPi
62 | - USB camera
63 | - Breadboard
64 | - Button
65 | - LED
66 |
67 | - Install node modules
68 |
69 | Install node modules for NodeJS in server folder
70 | - $ ~/Smart-bell/server $ npm install
71 |
72 | Install node modules for ReactJS in frontend folder
73 | - $ ~/Smart-bell/frontend $ npm install
74 |
75 | - Starting program
76 |
77 | Start MongoDB database
78 | - $ ~ sudo service mongodb start
79 |
80 | Start NodeJS server
81 | - $ ~/Smart-bell/server $ npm run dev
82 |
83 | Start Python application
84 | - $ ~/Smart-bell/python $ python usbcamera.py
85 |
86 | Start ReactJS application
87 | - $ ~/Smart-bell/frontend $ npm start
88 |
89 | Open ‘localhost:8080’ in the browser.
90 |
91 | ## Next steps
92 | - Deploying web application and database to the cloud. It will improve the performance of the python application running on RaspberryPi and will make web application available from everywhere.
93 | - Improving the security of the face recognition algorithm, that it could not be cheated with pictures.
94 | - Replace normal camera with 3D camera.
95 | - Implement the door locker opening mechanism via Bluetooth.
96 |
97 |
--------------------------------------------------------------------------------
/frontend/src/actions/index.js:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 | import {browserHistory} from 'react-router';
3 | import {
4 | AUTH_USER,
5 | UNAUTH_USER,
6 | AUTH_ERROR,
7 | FETCH_LOGS,
8 | FETCH_VISITORS,
9 | SOCKET_STATE,
10 | UPLOAD_DOCUMENT_SUCCESS,
11 | UPLOAD_DOCUMENT_FAIL,
12 | VISITOR_ADD_FAIL,
13 | VISITOR_ADD_SUCCESS,
14 | VISITOR_DELETE_FAIL,
15 | VISITOR_DELETE_SUCCESS,
16 | MAKE_PHOTO_FAIL,
17 | MAKE_PHOTO_SUCCESS,
18 | RESET_ADD_FORM
19 | } from './types.js';
20 |
21 | const ROOT_URL = 'http://localhost:3090';
22 |
23 | export function signinUser({email, password}) {
24 | return function (dispatch) {
25 | // Submit email/password to the server
26 | axios.post(`${ROOT_URL}/signin`, {email, password})
27 | .then(response => {
28 | // If request is good
29 | // - update state to indicate user is authenticated
30 | dispatch({type: AUTH_USER});
31 | // - save jwt token and id
32 | localStorage.setItem('token', response.data.token);
33 | localStorage.setItem('id', response.data.id);
34 | // redirect to another route
35 | browserHistory.push('/');
36 | })
37 | .catch(() => {
38 | // If request bad
39 | // - show an error to the user
40 | dispatch(authError('Invalid email or password'));
41 | });
42 |
43 | // If request is successful
44 | }
45 | }
46 |
47 | export function signupUser({email, password}) {
48 | return function (dispatch) {
49 | axios.post(`${ROOT_URL}/signup`, {email, password})
50 | .then(response => {
51 | dispatch({type: AUTH_USER});
52 | localStorage.setItem('token', response.data.token);
53 | localStorage.setItem('id', response.data.id);
54 | browserHistory.push('/');
55 | })
56 | .catch(response => {
57 | dispatch(authError(response.response.data.error));
58 | });
59 | }
60 | }
61 |
62 | export function authError(error) {
63 | return {
64 | type: AUTH_ERROR,
65 | payload: error
66 | };
67 | }
68 |
69 | export function signoutUser() {
70 | localStorage.removeItem('token');
71 | localStorage.removeItem('id');
72 |
73 | return {type: UNAUTH_USER};
74 | }
75 |
76 | export function fetchLogs() {
77 | return function (dispatch) {
78 | axios.get(`${ROOT_URL}/logs`, {
79 | headers: {authorization: localStorage.getItem('token')}
80 | })
81 | .then(response => {
82 | dispatch({
83 | type: FETCH_LOGS,
84 | payload: response.data.logs
85 | });
86 | });
87 | }
88 | }
89 |
90 | export function fetchVisitors() {
91 | return function (dispatch) {
92 | axios.get(`${ROOT_URL}/visitors`, {
93 | headers: {authorization: localStorage.getItem('token')}
94 | })
95 | .then(response => {
96 | dispatch({
97 | type: FETCH_VISITORS,
98 | payload: response.data.visitors
99 | });
100 | });
101 | }
102 | }
103 |
104 |
105 | export function addVisitor({firstname, lastname, email}) {
106 | return function (dispatch) {
107 | axios.post(`${ROOT_URL}/add_visitor`, {firstname, lastname, email})
108 | .then(response => {
109 | dispatch({
110 | type: VISITOR_ADD_SUCCESS,
111 | payload: 'success'
112 | });
113 | console.log("Visitor added");
114 | })
115 | .catch(response => {
116 | dispatch({
117 | type: VISITOR_ADD_FAIL,
118 | payload: 'fail'
119 | });
120 | console.log("Can't add a visitor");
121 | });
122 | }
123 | }
124 |
125 | export function deleteVisitor(id) {
126 | return function (dispatch) {
127 | axios.delete(`${ROOT_URL}/delete/${id}`, {
128 | headers: {authorization: localStorage.getItem('token')}
129 | })
130 | .then(response => {
131 | dispatch({
132 | type: VISITOR_DELETE_SUCCESS,
133 | payload: 'success'
134 | });
135 | console.log("Visitor deleted");
136 | })
137 | .catch(response => {
138 | dispatch({
139 | type: VISITOR_DELETE_FAIL,
140 | payload: 'fail'
141 | });
142 | console.log("Can't delete a visitor");
143 | });
144 | }
145 | }
146 |
147 | export function toogleAccess(id, value) {
148 | return function (dispatch) {
149 | axios.patch(`${ROOT_URL}/toogle/${id}/${value}`, {
150 | headers: {authorization: localStorage.getItem('token')}
151 | })
152 | .then(response => {
153 | console.log("Access changed");
154 | })
155 | .catch(response => {
156 | console.log("Can't change access");
157 | });
158 | }
159 | }
160 |
161 | export function addSocketToState(ws) {
162 | return {
163 | type: SOCKET_STATE,
164 | payload: ws
165 | };
166 | }
167 |
168 | export function uploadDocument({file}, ws) {
169 | let data = new FormData();
170 | data.append('file', file);
171 | return (dispatch) => {
172 | axios.post(`${ROOT_URL}/photo`, data)
173 | .then(response => {
174 | // it causes error when it sends success msg first before sending request to websocket when it isn't connected
175 | // that's why I changed the order // by jun
176 | ws.send("photo_upload");
177 | dispatch({type: UPLOAD_DOCUMENT_SUCCESS, payload: 'success'});
178 | })
179 | .catch(error => dispatch({type: UPLOAD_DOCUMENT_FAIL, payload: 'fail'}));
180 | };
181 | }
182 |
183 | export function photoMake(result) {
184 | return function (dispatch) {
185 | if (result == 'success') {
186 | dispatch({
187 | type: MAKE_PHOTO_SUCCESS,
188 | payload: 'success'
189 | });
190 | console.log('Photo make success');
191 | } else if (result == 'fail') {
192 | dispatch({
193 | type: MAKE_PHOTO_FAIL,
194 | payload: 'fail'
195 | });
196 | console.log('Photo make fail');
197 | }
198 | };
199 | }
200 |
201 | export function resetAddForm() {
202 | return function (dispatch) {
203 | dispatch({
204 | type: RESET_ADD_FORM,
205 | payload: 'reset'
206 | });
207 | console.log('Form reset');
208 | };
209 |
210 | }
211 |
--------------------------------------------------------------------------------
/frontend/src/components/add-visitor.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { withRouter } from 'react-router';
3 | import { reduxForm } from 'redux-form';
4 | import * as actions from '../actions';
5 |
6 | class AddVisitor extends Component {
7 | constructor(props) {
8 | super(props);
9 | this.makePhoto = this.makePhoto.bind(this);
10 | }
11 | componentWillMount() {
12 | this.props.resetAddForm();
13 | }
14 |
15 | componentWillUnmount() {
16 | //when user leaves the component without making photo or upload after adding visitor
17 | if(this.props.addFlag=='success' && this.props.photoMakeBell !='success'){
18 | onClick: alert('Adding visitor has been canceled.')
19 | this.onClickFormCancel();
20 | }
21 | }
22 |
23 | componentDidUpdate() {
24 | // form reset after adding visitor
25 | let addForm = document.getElementById('addVisitorForm');
26 | setTimeout(() => {
27 | if(this.props.addFlag=='success'&&this.props.photoMakeBell =='success') {
28 | onClick: alert("Succeed to add the visitor.");
29 | this.props.resetAddForm();
30 | this.resetFormValues(addForm);
31 | }
32 | else {
33 | }
34 | },100);
35 |
36 |
37 | }
38 | onClassAddForm(hideOrShow) {
39 | let newClass = "fadeIn"
40 | if (hideOrShow == 'success'){
41 | newClass = 'displayNone fadeIn';
42 | }
43 | else if (hideOrShow == 'fail') {
44 | onClick: alert('There is error while adding a visitor.\nPlease refresh the browser and do it again.')
45 | }
46 | return newClass;
47 | }
48 |
49 | onClassPhoto(hideOrShow) {
50 | let newClass = 'displayNone fadeIn';
51 | if (hideOrShow == 'success'){
52 | newClass = 'fadeIn';
53 | }
54 | return newClass;
55 | }
56 |
57 | handleFormSubmit(formProps) {
58 | this.props.addVisitor(formProps);
59 | setTimeout(() => {
60 | this.props.fetchVisitors();
61 | }, 100);
62 | }
63 |
64 | makePhoto() {
65 | this.props.ws.send("photo_make");
66 | this.props.photoMake();
67 | }
68 |
69 | onClassMakePhoto(hOs) {
70 | let newClass = "btn btn-primary";
71 | if(hOs == 'success') {
72 | //onClick: alert("success");
73 | }
74 | else if(hOs == 'fail') {
75 | onClick: alert("fail");
76 | }
77 | return newClass;
78 | }
79 |
80 | handleFileUpload = e => {
81 | this.props.uploadDocument({
82 | file: e.target.files[0]
83 | }, this.props.ws);
84 | }
85 |
86 | onClassFileUpload(hOs) {
87 | let newClass = "";
88 | if(hOs == 'success') {
89 | //onClick: alert("success");
90 | }
91 | else if(hOs == 'fail') {
92 | onClick: alert("fail");
93 |
94 | }
95 | return newClass;
96 | }
97 | deleteLatestVisitor() {
98 | this.props.ws.send("cancel");
99 | }
100 | onClickFormCancel = () => {
101 | if(this.props.addFlag == 'fail' || this.props.addFlag == 'none'){
102 | onClick: alert("Cancelling without adding basic information is unavailable.");
103 | return
104 | }
105 | let addForm = document.getElementById('addVisitorForm');
106 | this.props.fetchVisitors();
107 | this.deleteLatestVisitor();
108 | this.resetFormValues(addForm);
109 | }
110 |
111 | resetFormValues(addForm) {
112 | setTimeout(() => {
113 | this.props.resetAddForm();
114 | addForm.reset();
115 | const {resetForm} = this.props;
116 | resetForm();
117 | console.log('Form value reset');
118 | //console.log(addForm);
119 | /*console.log(this.props.values.firstname);
120 | this.props.setProps({
121 | values: {
122 | firstname: "none"
123 | }
124 | });
125 | console.log("change to"+this.props.firstname);
126 | console.log("change to"+this.props.values.firstname);*/
127 | }, 100);
128 | }
129 | render() {
130 | const { handleSubmit, fields: { firstname, lastname, email }} = this.props;
131 | //console.log(this.props.values);
132 | return (
133 |
134 |
152 |
153 |
Basic information is saved.
154 |
Please save your photo via either 'Make photo' or 'File upload'
155 |
160 |
161 |
162 |
163 |
164 | {/*
165 | this is addflag: {this.props.addFlag}
166 |
167 | this is make: {this.props.photoMakeBell}
168 |
169 | this is upload: {this.props.photoUpload}*/}
170 |