Skip to content

Commit c548abe

Browse files
author
Simon Townsend
committed
fixed db initialization issue and implemented formik for building forms
1 parent 669ff84 commit c548abe

File tree

9 files changed

+196
-84
lines changed

9 files changed

+196
-84
lines changed

package.json

+2
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@
99
"dist:dir": "yarn dist --dir -c.compression=store -c.mac.identity=null"
1010
},
1111
"dependencies": {
12+
"@types/fs-extra": "^5.0.4",
1213
"bluebird": "^3.5.1",
1314
"bootstrap": "^4.1.3",
15+
"formik": "^1.0.2",
1416
"fs-extra": "^7.0.0",
1517
"jquery": "^3.0.0",
1618
"popper.js": "^1.14.3",

src/main/index.ts

+10-8
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,8 @@ import { app, BrowserWindow, Event, ipcMain } from 'electron'
44
import * as path from 'path'
55
import { format as formatUrl } from 'url'
66
import SQL from 'sql.js';
7-
import * as Promise from 'bluebird';
87
import { DB_FILE_READY, GET_DB_FILE, WRITE_DB_DATA } from '../shared/constants/message-types';
9-
const fs = Promise.promisifyAll(require('fs-extra'));
8+
import * as fs from 'fs-extra';
109

1110
const isDevelopment = process.env.NODE_ENV !== 'production'
1211

@@ -73,12 +72,15 @@ const databaseFilePath = path.join(app.getPath('userData'), 'databases/starter.d
7372
ipcMain.on(GET_DB_FILE, async (event:Event) => {
7473

7574
try {
76-
let dbFile:Uint8Array|null = await fs.readFile(databaseFilePath);
77-
if (!dbFile) {
78-
const db = new SQL.Database();
79-
dbFile = db.export();
80-
const buffer = new Buffer(dbFile);
81-
await fs.writeFile(databaseFilePath, buffer);
75+
76+
let dbFile:Uint8Array|null;
77+
if (fs.pathExistsSync(databaseFilePath)) {
78+
dbFile = await fs.readFile(databaseFilePath);
79+
} else {
80+
const db = new SQL.Database();
81+
dbFile = db.export();
82+
const buffer = new Buffer(dbFile);
83+
await fs.writeFile(databaseFilePath, buffer);
8284
}
8385

8486
event.sender.send(DB_FILE_READY, dbFile);

src/renderer/actions/index.ts

+32-2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ import { DB_FILE_READY, GET_DB_FILE, WRITE_DB_DATA } from '../../shared/constant
99
export class ActionTypes {
1010
static readonly DB_READY = 'DB_READY';
1111
static readonly FETCH_DB = 'FETCH_DB';
12+
static readonly SAVE_USER = 'SAVE_USER';
13+
static readonly FETCH_USER = 'FETCH_USER';
14+
static readonly SET_USER = 'SET_USER';
1215
}
1316

1417
export function fetchDb() {
@@ -28,19 +31,46 @@ export function fetchDb() {
2831
type: 'sqljs',
2932
database: dbFile,
3033
entities: [UserEntity],
34+
synchronize: true,
3135
autoSave: true,
3236
autoSaveCallback: async (data: Uint8Array) => {
3337
ipcRenderer.send(WRITE_DB_DATA, data);
3438
}
3539
});
3640
}
3741

38-
dispatch(dbReadyAction(db));
42+
dispatch(dbReady(db));
3943
});
4044
}
4145
}
4246

43-
export const dbReadyAction = (db:Connection) => ({
47+
export const dbReady = (db:Connection) => ({
4448
type: ActionTypes.DB_READY,
4549
payload: db
50+
});
51+
52+
export function fetchUser() {
53+
return async (dispatch:Dispatch<AnyAction>, getState:()=>any) => {
54+
const { db } = getState();
55+
const userRepo = db.getRepository(UserEntity);
56+
const user = await userRepo.findOne(1);
57+
dispatch(setUser(user));
58+
}
59+
}
60+
61+
export function saveUser(userForm:any) {
62+
return async (dispatch:Dispatch<AnyAction>, getState:()=>any) => {
63+
const { db } = getState();
64+
const userRepo = db.getRepository(UserEntity);
65+
const user = new UserEntity(userForm);
66+
await userRepo.save(user);
67+
68+
const savedUser = await userRepo.findOne({name: user.name});
69+
dispatch(setUser(savedUser));
70+
}
71+
}
72+
73+
export const setUser = (user: UserEntity) => ({
74+
type: ActionTypes.SET_USER,
75+
payload: user
4676
});

src/renderer/components/Root.tsx

+3-5
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import * as React from 'react';
22
import './Root.scss';
3-
import { User } from './User';
43
import { SyncLoader } from 'react-spinners';
54
import { Connection } from 'typeorm';
5+
import UserContainer from '../containers/UserContainer';
66

77
interface RootProps {
88
db:Connection,
@@ -15,7 +15,7 @@ export class Root extends React.Component<RootProps, any> {
1515
this.props.fetchDb();
1616
}
1717

18-
render(){
18+
render(): any {
1919
let Content;
2020
if (!this.props.db) {
2121
Content = (
@@ -31,9 +31,7 @@ export class Root extends React.Component<RootProps, any> {
3131
</p>
3232
</div>
3333
<div className="flex-row">
34-
<User
35-
db={this.props.db}
36-
/>
34+
<UserContainer />
3735
</div>
3836
</div>
3937
);

src/renderer/components/User.tsx

+58-62
Original file line numberDiff line numberDiff line change
@@ -1,86 +1,82 @@
11
import * as React from 'react';
22
import './User.scss';
3-
import { FormEvent } from 'react';
43

54
import { UserEntity } from '../entities/UserEntity';
6-
import { Connection } from '../../../node_modules/typeorm';
7-
5+
import { Formik } from 'formik';
86

97
interface UserProps {
10-
db: Connection
8+
fetchUser: Function;
9+
saveUser: Function;
10+
user: UserEntity|null;
1111
}
1212
export class User extends React.Component<UserProps, any> {
13-
constructor(props: any){
14-
super(props);
15-
this.state = {
16-
formName: ""
17-
}
18-
19-
this.handleInputChange = this.handleInputChange.bind(this);
20-
this.handleFormSubmit = this.handleFormSubmit.bind(this);
21-
}
22-
23-
async componentDidMount() {
24-
let userRepo = this.props.db.getRepository(UserEntity);
25-
let user = await userRepo.findOne(1);
26-
let newState:any = {userRepo};
27-
if (user) {
28-
newState.user = user;
29-
}
30-
31-
this.setState(newState);
32-
}
3313

34-
async handleFormSubmit(event: any) {
35-
event.preventDefault();
36-
37-
if (this.state.formName) {
38-
let user = await this.state.userRepo.findOne({name: this.state.formName});
39-
if (!user) {
40-
user = new UserEntity();
41-
user.name = this.state.formName;
42-
await this.state.userRepo.save(user);
43-
44-
let savedUser = await this.state.userRepo.findOne({name: this.state.formName});
45-
this.setState({user: savedUser});
46-
}
14+
componentDidMount() {
15+
if (!this.props.user) {
16+
this.props.fetchUser();
4717
}
4818
}
49-
50-
handleInputChange(event: FormEvent<HTMLInputElement>) {
51-
const target = event.currentTarget;
52-
const value = target.type === 'checkbox' ? target.checked : target.value;
53-
const name = target.name;
54-
55-
this.setState({
56-
[name]: value
57-
});
58-
}
5919

6020
render(){
6121
let content;
62-
if (this.state.user) {
22+
const user = this.props.user;
23+
if (user) {
6324
content = (
6425
<div className='text-center'>
65-
<span>You're {this.state.user.name}!</span>
26+
<span>You're {user.name}!</span>
6627
</div>
6728
)
6829
} else {
6930
content = (
7031
<div className='col-sm-6 offset-sm-3'>
71-
<form onSubmit={this.handleFormSubmit}>
72-
<div className="form-group">
73-
<label>Name</label>
74-
<input
75-
name="formName"
76-
value={this.state.formName}
77-
onChange={this.handleInputChange}
78-
type="text"
79-
className="form-control"
80-
placeholder="Enter Name" />
81-
</div>
82-
<button type="submit" className="btn btn-primary">Submit</button>
83-
</form>
32+
<Formik
33+
initialValues={{
34+
name: ''
35+
}}
36+
validate={values => {
37+
let errors:any = {};
38+
if (values.name.length < 2) {
39+
errors.name = 'Name must be greater than 2 characters';
40+
}
41+
return errors;
42+
}}
43+
onSubmit={(
44+
values,
45+
{ setSubmitting, setErrors /* setValues and other goodies */ }
46+
) => {
47+
this.props.saveUser(values);
48+
}}
49+
render={({
50+
values,
51+
errors,
52+
touched,
53+
handleChange,
54+
handleBlur,
55+
handleSubmit,
56+
isSubmitting,
57+
}) => (
58+
<form onSubmit={handleSubmit}>
59+
<div className="form-group">
60+
<label>Name</label>
61+
<input
62+
type="text"
63+
name="name"
64+
className="form-control"
65+
onChange={handleChange}
66+
onBlur={handleBlur}
67+
value={values.name}
68+
/>
69+
{touched.name && errors.name && <div>{errors.name}</div>}
70+
</div>
71+
<button
72+
type="submit"
73+
className="btn btn-primary"
74+
disabled={isSubmitting}>
75+
Submit
76+
</button>
77+
</form>
78+
)}
79+
/>
8480
</div>
8581
)
8682
}
+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { connect } from 'react-redux'
2+
import { User } from '../components/User'
3+
import { saveUser, fetchUser } from '../actions';
4+
import { ThunkDispatch } from 'redux-thunk';
5+
6+
const mapStateToProps = (state:any) => {
7+
return {
8+
user: state.user,
9+
}
10+
}
11+
12+
const mapDispatchToProps = (dispatch:ThunkDispatch<any,any,any>) => {
13+
return {
14+
saveUser: (userForm:any) => dispatch(saveUser(userForm)),
15+
fetchUser: () => dispatch(fetchUser())
16+
}
17+
}
18+
19+
export default connect(
20+
mapStateToProps,
21+
mapDispatchToProps
22+
)(User)

src/renderer/entities/UserEntity.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,10 @@ export class UserEntity {
88

99
@Column()
1010
name!: string;
11-
11+
12+
constructor(userForm:any = null) {
13+
if (userForm) {
14+
this.name = userForm.name;
15+
}
16+
}
1217
}

src/renderer/reducers/index.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,15 @@ const initialState = {
44
db: null
55
};
66

7+
const set = (state:any, newState:any):any => {
8+
return Object.assign({}, state, newState);
9+
}
710
const rootReducer = (state = initialState, action:any) => {
811
switch (action.type) {
912
case ActionTypes.DB_READY:
10-
return Object.assign({}, state, {db: action.payload});
11-
13+
return set(state, {db: action.payload});
14+
case ActionTypes.SET_USER:
15+
return set(state, {user: action.payload});
1216
default:
1317
return state;
1418
}

0 commit comments

Comments
 (0)