import { appName } from "../config";
import firebase from "firebase";
import { Record } from "immutable";
import { all, take, apply, takeEvery, put, call } from "redux-saga/effects";
import { replace } from "react-router-redux";
import { eventChannel } from "redux-saga";
const ReducerRecord = Record({
user: null,
error: null,
loading: false
});
export const moduleName = "auth";
export const SIGN_UP_REQUEST = `${appName}/${moduleName}/SIGN_UP_REQUEST`;
export const SIGN_UP_SUCCESS = `${appName}/${moduleName}/SIGN_UP_SUCCESS`;
export const SIGN_UP_ERROR = `${appName}/${moduleName}/SIGN_UP_ERROR`;
export const SIGN_IN_REQUEST = `${appName}/${moduleName}/SIGN_IN_REQUEST`;
export const SIGN_IN_SUCCESS = `${appName}/${moduleName}/SIGN_IN_SUCCESS`;
export const SIGN_IN_ERROR = `${appName}/${moduleName}/SIGN_IN_ERROR`;
export const SIGN_OUT_REQUEST = `${appName}/${moduleName}/SIGN_OUT_REQUEST`;
export const SIGN_OUT_SUCCESS = `${appName}/${moduleName}/SIGN_OUT_SUCCESS`;
export default function authReducer(state = ReducerRecord(), action) {
const { type } = action;
switch (type) {
case SIGN_UP_REQUEST: {
return state.set("loading", true);
}
case SIGN_IN_SUCCESS: {
return state
.set("loading", false)
.set("user", action.payload.user)
.set("error", null);
}
case SIGN_OUT_SUCCESS: {
return new ReducerRecord();
}
default: {
return state;
}
}
}
export function signIn(email, password) {
return {
type: SIGN_IN_REQUEST,
payload: {
email,
password
}
};
}
export function signUp(email, password) {
return {
type: SIGN_UP_REQUEST,
payload: {
email,
password
}
};
}
export function signOut() {
return {
type: SIGN_OUT_REQUEST
}
}
export const signInSaga = function * () {
const auth = firebase.auth();
const action = yield take(SIGN_IN_REQUEST);
const user = yield call([auth, auth.signInWithEmailAndPassword], action.payload.email, action.payload.password);
yield put({
type: SIGN_IN_SUCCESS,
payload: user
});
yield put(replace("/"));
};
export const signOutSaga = function * () {
const auth = firebase.auth();
yield apply(auth, auth.signOut);
}
export const signUpSaga = function * () {
const auth = firebase.auth();
while (true) {
const action = yield take(SIGN_UP_REQUEST);
try {
const user = yield call([auth, auth.createUserWithEmailAndPassword], action.payload.email, action.payload.password);
yield put({
type: SIGN_UP_SUCCESS,
payload: {
user
}
});
yield put(replace("/"));
} catch (error) {
yield put({
type: SIGN_UP_ERROR,
error
});
}
}
};
const createAuthChannel = () => eventChannel(emit => firebase.auth().onAuthStateChanged(user => emit({ user })))
export const watchStatusChangeSaga = function * () {
const chan = yield call(createAuthChannel);
while (true) {
const { user } = yield take(chan);
if (user) {
yield put({
type: SIGN_IN_SUCCESS,
payload: { user }
});
} else {
yield put({
type: SIGN_OUT_SUCCESS,
payload: { user }
});
yield put(replace('/'));
}
}
}
export const saga = function * () {
yield all([
takeEvery(SIGN_IN_REQUEST, signInSaga),
takeEvery(SIGN_OUT_REQUEST, signOutSaga),
signUpSaga(),
watchStatusChangeSaga()
]);
};
users: {
"email1@mail.com": { ... },
"email2@mail.com": { ... },
"email3@mail.com": { ... },
"email4@mail.com": { ... },
}
import React from "react";
import { connect } from "react-redux";
import { loadArticleComments } from "../AC";
import "./CommentList.css";
import Comment from "./Comment";
import CommentForm from "./CommentForm";
import toggleOpen from "../decorators/toggleOpen";
class CommentList extends React.Component {
componentWillReceiveProps({ isOpen, article, loadArticleComments }) {
if (!this.props.isOpen && isOpen && !article.commentsLoading && !article.commentsLoaded) {
loadArticleComments(article.id)
}
}
getCommentsBody = () => {
const { article: { comments = [], id } } = this.props;
if (!comments) {
return (
<div>
<div>empty</div>
<CommentForm articleId = { id } />
</div>
);
}
return (
<div className="comment-list">
<ul className="list-group">
{
comments.map(id => (
<li className="list-group-item" key = { id }>
<Comment id = { id } /> // Рендер комментария
</li>
))
}
</ul>
<CommentForm articleId = { id } />
</div>
);
}
render() {
return (
<div>
<button className="btn btn-dark" onClick = { this.props.handleToggle }>{ this.props.isOpen ? "close comments" : "open comments" }</button>
{ this.props.isOpen && this.getCommentsBody() }
</div>
);
}
}
export default connect(null, {
loadArticleComments
})(toggleOpen(CommentList));
import React from "react";
import { connect } from "react-redux";
import { commentSelectorFactory } from "../selectors";
const Comment = ({ comment }) => (
<div>
<h5>{ comment.user }</h5>
{ comment.text }
</div>
);
export default connect(
() => {
const commentSelector = commentSelectorFactory();
return (state, ownProps) => {
return {
comment: commentSelector(state, ownProps) // Запрос комментария из селектора
};
};
}
)(Comment);
export const commentSelectorFactory = () => createSelector(commentsGetter, idGetter, (comments, id) => {
return comments.getIn(["entities", id]); // Получить комментарий по id
});
import { arrToMap } from "../helpers";
import { OrderedMap, Record } from "immutable";
const CommentRecord = Record({
id: null,
text: "",
user: ""
});
const ReducerState = Record({
entities: new OrderedMap({})
});
const defaultState = new ReducerState();
export default (commentsState = defaultState, action) => {
switch (action.type) {
case "ADD_COMMENT": {
return commentsState.setIn(["entities", action.randomId], new CommentRecord({ ...action.payload.comment, id: action.ramdomId }));
}
case "LOAD_ARTICLE_COMMENTS_SUCCESS": { // В middleware добавляется _SUCCESS
return commentsState.mergeIn(['entities'], arrToMap(action.response, CommentRecord));
}
default: {
return commentsState;
}
}
};
import { OrderedMap } from "immutable";
export function arrToMap(arr, RecordModel) {
return arr.reduce((acc, el) => acc.set(el.id, RecordModel ? new RecordModel(el) : el), new OrderedMap({}))
}
export function loadArticleComments(articleId) {
console.log("Action creator loadArticleComments: ");
return {
type: "LOAD_ARTICLE_COMMENTS",
payload: { articleId },
callAPI: `/api/comment?article=${articleId}`
}
}
export default store => next => action => {
const { callAPI, type, ...rest } = action;
if (!callAPI) {
return next(action);
}
next({
...rest,
type: type + "_START"
});
fetch(callAPI)
.then(res => res.json())
.then(response => next({
...rest,
type: type + "_SUCCESS",
response
})
);
};
for (let i = 1; i <= 2; i += 1)
После регистрации теперь пользователь добавляется в БД, но теперь не ясно, как сделать так чтобы как бы связать пользователей в firebase с моей коллекцией в БД firebase. У меня сейчас получается что в БД попадают только новые пользователи, а старые как были в тени так и остались. Где и как это можно реализовать?