diff --git a/src/components/Add.jsx b/src/components/Add.tsx
similarity index 82%
rename from src/components/Add.jsx
rename to src/components/Add.tsx
index e0062e5..b1cf2d9 100644
--- a/src/components/Add.jsx
+++ b/src/components/Add.tsx
@@ -1,12 +1,17 @@
import React from "react";
-import useForm from "../hooks/useForm";
-import useFirebase from "../hooks/useFirebase";
+import useForm, { InputInterface, ActionInterface } from "../hooks/useForm";
+import useFirebase, { WordInterface } from "../hooks/useFirebase";
+
+interface PropsInterface {
+ onAdd: Function;
+}
const INITIAL_STATE = [
{
name: "type",
- type: "select",
+ type: "select" as const,
+ value: "",
placeholder: "Type",
required: true,
options: [
@@ -19,7 +24,7 @@ const INITIAL_STATE = [
},
{
name: "article",
- type: "select",
+ type: "select" as const,
value: "",
required: true,
options: [
@@ -33,26 +38,26 @@ const INITIAL_STATE = [
{
name: "word",
placeholder: "Word",
- type: "text",
+ type: "text" as const,
value: "",
required: true
},
{
name: "meaning",
placeholder: "Meaning",
- type: "text",
+ type: "text" as const,
value: "",
required: true
},
{
name: "note",
placeholder: "Note",
- type: "text",
+ type: "text" as const,
value: ""
}
];
-function reducer(state, action) {
+function reducer(state: InputInterface[], action: ActionInterface) {
const { type, name, value } = action;
if (type === "edit" && name === "type") {
@@ -77,11 +82,11 @@ function reducer(state, action) {
return state;
}
-function validator(inputs) {
+function validator(inputs: InputInterface[]) {
const inputMap = inputs.reduce((map, input) => {
map[input.name] = input;
return map;
- }, {});
+ }, {} as { [key: string]: InputInterface });
const requiredInputs = !inputs.some(input => {
if (input.required && !input.value) {
@@ -103,7 +108,7 @@ function validator(inputs) {
}
}
-function Add({ onAdd }) {
+function Add({ onAdd }: PropsInterface) {
const { state, isValid, change, reset } = useForm(INITIAL_STATE, {
reducer,
validator
@@ -116,7 +121,7 @@ function Add({ onAdd }) {
...prev,
[property.name]: property.value
};
- }, {});
+ }, {} as WordInterface);
addWordToFirebase(word).then(() => {
reset();
onAdd();
@@ -135,7 +140,7 @@ function Add({ onAdd }) {
onChange={change}
disabled={input.disabled}
>
- {input.options.map(option => (
+ {input.options?.map(option => (
diff --git a/src/components/App.jsx b/src/components/App.tsx
similarity index 69%
rename from src/components/App.jsx
rename to src/components/App.tsx
index 0206003..1ab025e 100644
--- a/src/components/App.jsx
+++ b/src/components/App.tsx
@@ -1,19 +1,23 @@
import React, { useState, useEffect } from "react";
import "./App.css";
-import useFirebase from "../hooks/useFirebase";
+import useFirebase, { WordInterface } from "../hooks/useFirebase";
import Login from "./Login";
import Add from "./Add";
import View from "./View";
+interface Global {
+ logout?: Function;
+}
+
function App() {
- const [words, setWords] = useState([]);
+ const [words, setWords] = useState([]);
const { user, getAllWords, logout } = useFirebase();
- window.logout = logout;
+ (window as Global).logout = logout;
const getWords = () => {
- getAllWords().then(setWords);
+ getAllWords().then(words => words && setWords(words));
};
useEffect(getWords, [getAllWords]);
diff --git a/src/components/Login.jsx b/src/components/Login.tsx
similarity index 89%
rename from src/components/Login.jsx
rename to src/components/Login.tsx
index 523d109..b8d3709 100644
--- a/src/components/Login.jsx
+++ b/src/components/Login.tsx
@@ -6,14 +6,14 @@ import useFirebase from "../hooks/useFirebase";
const INITIAL_STATE = [
{
placeholder: "Email",
- type: "email",
+ type: "email" as const,
name: "email",
value: "blessanm86@gmail.com",
required: true
},
{
placeholder: "Password",
- type: "password",
+ type: "password" as const,
name: "password",
value: "",
required: true
@@ -30,7 +30,7 @@ function Login() {
...prev,
[property.name]: property.value
};
- }, {});
+ }, {} as { email: string; password: string });
loginToFirebase(email, password);
reset();
};
diff --git a/src/components/View.jsx b/src/components/View.tsx
similarity index 77%
rename from src/components/View.jsx
rename to src/components/View.tsx
index 086e044..a1646cb 100644
--- a/src/components/View.jsx
+++ b/src/components/View.tsx
@@ -1,6 +1,11 @@
import React from "react";
+import { WordInterface } from "../hooks/useFirebase";
-function View({ words = [] }) {
+interface PropsInterface {
+ words: WordInterface[];
+}
+
+function View({ words = [] }: PropsInterface) {
return (
{words.map(({ word, article, meaning, note, type }, index) => (
diff --git a/src/hooks/useFirebase.js b/src/hooks/useFirebase.ts
similarity index 62%
rename from src/hooks/useFirebase.js
rename to src/hooks/useFirebase.ts
index c56f4ed..974f762 100644
--- a/src/hooks/useFirebase.js
+++ b/src/hooks/useFirebase.ts
@@ -3,6 +3,15 @@ import * as firebase from "firebase/app";
import "firebase/auth";
import "firebase/firestore";
+export interface WordInterface {
+ article: string;
+ meaning: string;
+ note: string;
+ timestamp: firebase.firestore.Timestamp;
+ type: string;
+ word: string;
+}
+
const firebaseConfig = {
apiKey: "AIzaSyAWznMXfEF-FMt9OUT10Twzxr382zfs3MU",
authDomain: "mein-woerterbuch.firebaseapp.com",
@@ -14,7 +23,7 @@ const firebaseConfig = {
measurementId: "G-06SEN5MFN2"
};
-function loginToFirebase(email, password) {
+function loginToFirebase(email: string, password: string): void {
firebase
.auth()
.signInWithEmailAndPassword(email, password)
@@ -34,7 +43,7 @@ function logout() {
firebase.auth().signOut();
}
-function addWordToFirebase(word) {
+function addWordToFirebase(word: WordInterface): Promise {
word.timestamp = firebase.firestore.Timestamp.now();
return firebase
@@ -42,39 +51,45 @@ function addWordToFirebase(word) {
.collection("woerte")
.add(word)
.then(function(docRef) {
- console.log("Document written with ID: ", docRef.id);
+ const result = `Document written with ID: ${docRef.id}`;
+ console.log(result);
+ return result;
})
.catch(function(error) {
- console.error("Error adding document: ", error);
+ const result = `Error adding document: ${error}`;
+ console.error(result);
+ return result;
});
}
-function getAllWords() {
+function getAllWords(): Promise {
return firebase
.firestore()
.collection("woerte")
.orderBy("timestamp", "desc")
.get()
.then(snapshot => {
- const words = [];
- snapshot.forEach(doc => words.push(doc.data()));
+ const words: WordInterface[] = [];
+ snapshot.forEach(doc => words.push(doc.data() as WordInterface));
return words;
})
- .catch(err => console.log(err));
+ .catch(error => {
+ console.log(error);
+ });
}
-let firbaseAuthStateListener;
-
function useFirebase() {
- const [user, setUser] = useState(null);
+ const [user, setUser] = useState(null);
!firebase.apps.length && firebase.initializeApp(firebaseConfig);
- useEffect(() => {
- firbaseAuthStateListener = firebase.auth().onAuthStateChanged(setUser);
-
- return () => firbaseAuthStateListener();
- }, []);
+ useEffect(
+ () =>
+ firebase.auth().onAuthStateChanged(user => {
+ user && setUser(user);
+ }),
+ []
+ );
return {
user,
diff --git a/src/hooks/useForm.ts b/src/hooks/useForm.ts
index 5ac90fe..2161c9b 100644
--- a/src/hooks/useForm.ts
+++ b/src/hooks/useForm.ts
@@ -1,8 +1,8 @@
-import { useReducer, ChangeEvent } from "react";
+import { useReducer, ChangeEventHandler, ChangeEvent } from "react";
-interface Input {
+export interface InputInterface {
name: string;
- type: string;
+ type: "text" | "password" | "email" | "select";
placeholder?: string;
required?: boolean;
disabled?: boolean;
@@ -10,26 +10,31 @@ interface Input {
value: string;
}
-interface Options {
+interface OptionsInterface {
reducer?: Function;
validator?: Function;
}
-interface State {
- state: Array;
+interface FormInterface {
+ state: InputInterface[];
isValid: boolean;
- change: Function;
+ change: ChangeEventHandler;
reset: Function;
}
-interface Action {
+export interface ActionInterface {
type: string;
name?: string;
value?: string;
}
-function useForm(inputs: Array, options: Options = {}): State {
- function change(evt: ChangeEvent) {
+function useForm(
+ inputs: InputInterface[],
+ options: OptionsInterface = {}
+): FormInterface {
+ function change(
+ evt: ChangeEvent
+ ): void {
const {
target: { name, value }
} = evt;
@@ -40,7 +45,7 @@ function useForm(inputs: Array, options: Options = {}): State {
dispatch({ type: "reset" });
}
- function validator(inputs: Array) {
+ function validator(inputs: InputInterface[]) {
return !inputs.some(input => {
if (input.required && !input.value) {
return true;
@@ -50,7 +55,10 @@ function useForm(inputs: Array, options: Options = {}): State {
});
}
- function reducer(state: State, action: Action): State {
+ function reducer(
+ state: FormInterface,
+ action: ActionInterface
+ ): FormInterface {
const { state: inputs } = state;
const { type, name, value } = action;