4. usersディレクトリ
operators.js(actions.jsの関数を呼び出しつつユーザーデータを変更する)
import { db, auth, FirebaseTimestamp } from '../../firebase/index';
import { editProfileStateAction, fecthOrdersHistoryAction, fetchProductsInCartAction, signOutAction, signInAction } from './actions';
import { push, goBack } from 'connected-react-router';
import { isValidEmailFormat, isValidRequiredInput } from '../../function/common';
import { hideLoadingAction, showLoadingAction } from '../loading/actions';
import { initProductsAction } from '../products/actions';
const usersRef = db.collection('users');
export const addProductToCart = (addedProduct) => {
return async (dispatch, getState) => {
const uid = getState().users.uid;
const cartRef = usersRef.doc(uid).collection('cart').doc();
addedProduct['cartId'] = cartRef.id;
await cartRef.set(addedProduct);
dispatch(push('/cart'))
}
}
export const editUserProfile = (iconPath, introduction, uid, username) => {
return aysnc (dispatch) => {
const updateValue = {
icon_path: iconPath,
username: username
};
usersRef.doc(uid).update(updateValue)
.then(() => {
alert('ユーザー情報を更新しました');
dispatch(editProfilesStateAction(updateValue));
dispatch(goBack())
}).catch((error) => {
console.error(error)
alert('ユーザー情報の更新に失敗しました')
})
}
};
export const fetchOrdersHistory = () => {
return async (dispatch, getState) => {
const uid = getState().users.uid;
const list = []
usersRef.doc(uid).collection('orders')
.orderBy('updated_at', 'desc').get()
.then(snapshots => {
snapshots.forEach(snapshot => {
const data = snapshot.data();
list.push(data)
});
dispatch(fetchOrdersHistoryAction(list))
})
}
};
export const listenAuthState = () => {
return async (dispatch) => {
return auth.onAuthStateChanged(user => {
if (user) {
usersRef.doc(user.uid).get()
.then(snapshot => {
const data = snapshot.data()
if (!data) {
throw new Error('ユーザーデータが存在しません')
}
dispatch(signInAction({
customer_id: (data.customer_id) ? data.customer_id : "",
email: data.email,
isSignedIn: true,
payment_method_id: (data.payment_method_id) ? data.payment_method_id : "",
role: data.role,
uid: user.uid,
username: data.username,
}))
})
} else {
dispatch(push('/signin'))
}
})
}
};
export const signUp = (username, email, password, confirmPassword) => {
return async (dispatch) => {
if (!isValidRequiredInput(email, password, confirmPassword)) {
alert('必須項目が未入力です');
return false
}
if (!isValidRequiredInput(email)) {
alert('メールアドレスの形式が不正です');
return false
}
if (password !== confirmPassword) { <--- confirmPasswordは引数
alert('パスワードが一致しません');
return false
}
if (password.length < 6) {
alert('パスワードは6文字以上で入力してください')
return false
}
return auth.createUserWithEmailAndPassword(email, password)
.then(result => {
dispatch(showLoadinAction("Sign up ...")) <--- loadingディレクトリのメソッドを実行
const user = result.user;
if (user) {
const uid = user.uid;
const timestamp = FirebaseTimestamp.now();
const userInitialData = {
customer_id: "",
created_at: timestamp,
email: email,
role: "customer",
payment_method_id: "",
uid: uid,
updated_at: timestamp,
username: username
};
usersRef.doc(uid).set(userInitialData).then(async () => {
dispatch(push('/'))
dispatch(hideLoadingAction())
})
}
}).catch((error) => {
dispatch(hideLoadingAction())
alert('アカウント登録に失敗しました')
throw new Error(error)
})
}
}
export const resetPassword = (email) => {
return async (dispatch) => {
if (!isValidEmailFormat(email)) {
alert('メールアドレスが不正です')
return false
} else {
return auth.sendPasswordResetEmail(email)
.then(() => {
alert('入力されたアドレス宛にパスワードリセットのメールをお送りしましたのでご確認ください')
dispatch(push('/signin'))
}).catch(() => {
alert('登録されていないメールアドレスです')
})
}
}
}
export const saveAddress = (address) => {
return async (dispatch, getState) => {
const state = getState()
const userId = state.users.uid
return usersRef.doc(userId).collection('addresses').doc(userId).set(address)
.then(() => {
alert('入力いただいた情報を保存しました')
dispatch(push('/bank'))
}).catch(error => {
alert('情報の保存に失敗しました')
throw new Error(error)
})
}
}
export const signIn = (email, password) => {
return async (dispatch) => {
dispatch(showLoadingAction("Sign in ..."));
if (!isValidRequiredInput(email, password)) {
dispatch(hideLoadingAction())
alert('メールアドレスかパスワードが未入力です')
return false
}
if (!isValidEmailFormat(email)) {
dispatch(hideLoadingAction());
alert('メールアドレスの形式が不正です')
return false
}
return auth.signInWithEmailAndPassword(email, password)
.then(result => {
const userState = result.user
if (!userState) {
dispatch(hideLoadingAction());
throw new Error('ユーザーIDを取得できません')
}
const userId = userState.uid;
return usersRef.doc(userId).get().then(snapshot => {
const data = snapshot.data();
if (!data) {
dispatch(hideLoadingAction());
throw new Error('ユーザーデータが存在しません')
}
dispatch(signInAction({
customer_id: (data.customer_id) ? data.customer_id : "",
email: data.email,
isSignedIn: true,
role: data.role,
payment_method_id: (data.payment_method_id) ? data.payment_method_id : "",
uid: userId,
username: data.username,
}));
dispatch(hideLoadingAction());
dispatch(push('/'))
})
}).catch(() => {
dispatch(hideLoadingAction());
})
}
};
export const signOut = () => {
return async (dispatch, getState) => {
dispatch(shoeLoadingAction("Sign out ..."));
const uid = getState().users.uid
// userのcartからproductsをdeleteする
await usersRef.doc(uid).collection('cart').get()
.then(snapshots => {
snapshots.forEach(snapshot => {
usersRef.doc(uid).collection('cart').doc(snapshot.id).delete()
})
});
//
auth.signOut().then(() => {
dispatch(signOutAction());
dispatch(initProductsAction());
dispatch(hideLoadingAction());
dispatch(push('/signin'));
}).catch(() => {
dispatch(hideLoadingAction())
throw new Error('ログアウトに失敗しました')
})
}
}
actions.js(storeのuserデータを内容変更するための関数をまとめたファイル)
export const EDIT_USER_PROFILE = "EDIT_USER_PROFILE";
export const editProfileStateAction = (userProfile) => {
return {
type: "EDIT_USER_PROFILE", <--- actionの種類
payload: userProfile <--- actionで必要なデータがオブジェクト形式(key:Value)で入っています
}
};
export const FETCH_ORDERS_HISTORY = "FETCH_ORDERS_HISTORY";
export const fetchOrdersHistoryAction = (orders) => {
return {
type: "FETCH_ORDERS_HISTORY",
payload: orders
}
};
export const FETCH_PRODUCTS_IN_CART = "FETCH_PRODUCTS_IN_CART"
export const fetchProductsInCartAction = (products) => {
return {
type: "FETCH_PRODUCTS_IN_CART",
payload: products
}
};
export const SING_IN = "SIGN_IN";
export const signInAction = (userState) => {
return {
type: "SIGN_IN",
payload: userState
}
};
export const SIGN_OUT = "SIGN_OUT";
export const signOutAction = () => {
return {
type: "SIGN_OUT",
payload: null
}
};
export const UPDATE_USER_STATE = "UPDATE_USER_STATE";
export const updateUsersStateAction = (userState) => {
return {
type: "UPDATE_USER_STATE",
payload: userState
}
}
reducers.js(actionのtypeに応じてstateの内容を更新してstoreに伝えるファイル)
import * as Actions from './actions';
import { initialState } from '../store/initialState';
export const UsersReducer = (state = initialState.users, action) => {
switch (action.type) { <--- actionのtypeに応じて処理をします
case Actions.EDIT_USER_PROFILE:
return {
...state,
icon_path: action.payload.icon_path,
username: action.payload.username
};
case Actions.FETCH_ORDERS_HISTORY:
return {
...state,
orders: [...action.payload]
};
case Actions.FETCH_PRODUCTS_IN_CART:
return {
...state,
cart: [...action.payload]
};
case Actions.SIGN_IN:
return {
...state,
...action.payload
};
case Action.SIGN_OUT:
return {
...initialState.users,
};
case Actions.UPDATE_USER_STATE:
return {
...state,
...action.payload
};
default:
return state
}
};
selectors.js (storeからuserデータを取得するための関数をまとめたファイル)
import { createSelector } from "reselect";
const usersSelector = (state) => state.users; <--- stateからusers部分を抽出しています
export const getCustomerId = createSelector( <--- ※1
[usersSelector], <--- usersSelectorの中から
state => state.customer_id <--- customer_idのデータを取得します
);
export const getOrderHistory = createSelector(
[usersSelector],
state => state.orders
);
export const getProductsInCart = createSelector(
[usersSelector],
state => state.cart
);
export const getPaymentMethodId = createSelector(
[usersSelector],
state => state.payment_method_id
);
export const getSignedIn = createSelector(
[usersSelector],
state => state.username
);
export const getUserId = createSelector(
[usersSelector],
state => state.uid
);
export const getUserRole = createSelector(
[usersSelector],
state => state.role
);
※1 … getCustomerIdはstateから必要なデータ(customer_id)を取得するための関数です
createSelectorはキャッシュ機能がついており、入力値が変わらない限り、再計算せずに前回の結果を返します
これによりcreateSelectorを使うことでデータを効率的に取得できます
BACK