Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Users/html react UI #1

Open
wants to merge 5 commits into
base: users/forms2
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 75 additions & 0 deletions src/app/api/fake.api/comments.api.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
const comments = [
{
_id: "67rdca3eeb7f6fg",
userId: "67rdca3eeb7f6fgeed471815",
pageId: "67rdca3eeb7f6fgeed471815",
content: "Lorem ipsum dolor",
created_at: "1633576399367"
},
{
_id: "67rdca3eeb7f6fgdasd",
pageId: "67rdca3eeb7f6fgeed471815",
userId: "67rdca3eeb7f6fgeed471815",
content: "Lorem ipsum dolor and etc",
created_at: "1633573058520"
},
{
_id: "67rdca3eeb7f6fgdaasd",
pageId: "67rdca3eeb7f6fgeed471817",
userId: "67rdca3eeb7f6fgeed471815",
content: "Lorem ipsum dolor and etc",
created_at: "1633573058520"
}
];
if (!localStorage.getItem("comments")) {
localStorage.setItem("comments", JSON.stringify(comments));
}
const fetchAll = () =>
new Promise((resolve) => {
window.setTimeout(function () {
resolve(comments);
}, 200);
});

const fetchCommentsForUser = (userId) =>
new Promise((resolve) => {
window.setTimeout(function () {
resolve(
JSON.parse(localStorage.getItem("comments")).filter(
(c) => c.pageId === userId
)
);
}, 200);
});
const add = (data) =>
new Promise((resolve) => {
window.setTimeout(function () {
const comments = JSON.parse(localStorage.getItem("comments"));
const newComment = {
...data,
created_at: Date.now(),
_id: Math.random().toString(36).substr(2, 9)
};
comments.push(newComment);
localStorage.setItem("comments", JSON.stringify(comments));
resolve(newComment);
}, 200);
});

const remove = (id) =>
new Promise((resolve) => {
window.setTimeout(function () {
const comments = JSON.parse(localStorage.getItem("comments"));
const newComments = comments.filter((x) => x._id !== id);
console.log(id);
console.log(newComments);
localStorage.setItem("comments", JSON.stringify(newComments));
resolve(id);
}, 200);
});
export default {
fetchAll,
fetchCommentsForUser,
add,
remove
};
4 changes: 2 additions & 2 deletions src/app/api/fake.api/user.api.js
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,6 @@ const getById = (id) =>
});
export default {
fetchAll,
getById,
update
update,
getById
};
14 changes: 14 additions & 0 deletions src/app/components/common/BackButton.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from "react";
import { useHistory } from "react-router";

const BackHistoryButton = () => {
const history = useHistory();
return (
<button className="btn btn-primary" onClick={() => history.goBack()}>
<i className="bi bi-caret-left-fill "></i>
Назад
</button>
);
};

export default BackHistoryButton;
15 changes: 15 additions & 0 deletions src/app/components/common/comments/CommentsList.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from "react";
import PropTypes from "prop-types";
import Comment from "./comment";

const CommentsList = ({ comments, onRemove }) => {
return comments.map((comment) => (
<Comment key={comment._id} {...comment} onRemove={onRemove} />
));
};
CommentsList.propTypes = {
comments: PropTypes.array,
onRemove: PropTypes.func
};

export default CommentsList;
109 changes: 109 additions & 0 deletions src/app/components/common/comments/addCommentForm.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import React, { useState, useEffect } from "react";
import PropTypes from "prop-types";
import { validator } from "../../../utils/validator";
import SelectField from "../form/selectField";
import TextareaSelectedField from "../form/textareaSelectedField";
import api from "../../../api";

const initialDate = { userId: "", content: "" };
const AddCommentForm = ({ onSubmit }) => {
const [data, setData] = useState(initialDate);
const [errors, setErrors] = useState({ userId: "", content: "" });
const [user, setUser] = useState([]);

const validatorConfig = {
userId: {
isRequared: {
message: "Выберете от чьего имени вы хотите отправить сообщение"
}
},
content: {
isRequared: {
message: "Сообщение не может быть пустым"
}
}
};

useEffect(() => {
api.users.fetchAll().then((data) => {
const listOfUsers = Object.keys(data).map((userName) => ({
value: data[userName]._id,
label: data[userName].name
}));
setUser(listOfUsers);
});
}, []);

useEffect(() => {
validate();
}, [data]);

const validate = () => {
const errors = validator(data, validatorConfig);
setErrors(errors);
return Object.keys(errors).length === 0;
};

const isValid = Object.keys(errors).length === 0;

const handleChange = (target) => {
setData((prevState) => ({
...prevState,
[target.name]: target.value
}));
};

const clearForm = () => {
setData(initialDate);
setErrors({});
};

const submitHandler = (event) => {
event.preventDefault();
const isValid = validate();
if (!isValid) return;
onSubmit(data);
clearForm();
};
console.log(data);

return (
<>
<form onSubmit={submitHandler}>
<h3 className="card-body">New comment</h3>
<span className="card-body">
<SelectField
defaultOption="Выберете пользователя"
name="userId"
options={user}
onChange={handleChange}
value={data.userId}
error={errors.userId}
/>
<TextareaSelectedField
type="text"
label="Сообщение"
name="content"
value={data.content}
onChange={handleChange}
error={errors.content}
/>
<div className="d-flex justify-content-end">
<button
type="submit"
className="btn btn-info text-dark btn-outline-info"
disabled={!isValid}
>
Опубликовать
</button>
</div>
</span>
</form>
</>
);
};
AddCommentForm.propTypes = {
onSubmit: PropTypes.func
};

export default AddCommentForm;
83 changes: 83 additions & 0 deletions src/app/components/common/comments/comment.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import React, { useEffect, useState } from "react";
import PropTypes from "prop-types";
import api from "../../../api";
import { displayDate } from "../../../utils/displayDate";

const Comment = ({
content,
userId,
_id: id,
created_at: created,
onRemove
}) => {
const [user, setUser] = useState();
const [isLoading, setIsLoading] = useState();

useEffect(() => {
setIsLoading(true);
api.users.getById(userId).then((data) => {
setUser(data);
setIsLoading(false);
});
}, []);

return (
<div className="bg-light card-body mb-3">
<div className="row">
{isLoading ? (
<div
className="badge text-bg-secondary"
style={{ display: "", maxWidth: "150px" }}
>
Loading
</div>
) : (
<div className="col">
<div className="d-flex flex-start ">
<img
src={`https://avatars.dicebear.com/api/avataaars/${(
Math.random() + 1
)
.toString(36)
.substring(7)}.svg`}
className="rounded-circle shadow-1-strong me-3"
alt="avatar"
width="65"
height="65"
/>
<div className="flex-grow-1 flex-shrink-1">
<div className="mb-4">
<div className="d-flex justify-content-between align-items-center">
<p className="mb-1 ">
{user && user.name}
<span className="small m-3">
{"- "}
{displayDate(created)}
</span>
</p>
<button
className="btn btn-sm text-primary d-flex align-items-center"
onClick={() => onRemove(id)}
>
<i className="bi bi-x-lg"></i>
</button>
</div>
<p className="small mb-0">{content}</p>
</div>
</div>
</div>
</div>
)}
</div>
</div>
);
};
Comment.propTypes = {
content: PropTypes.string,
userId: PropTypes.string,
created_at: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
onRemove: PropTypes.func,
_id: PropTypes.string
};

export default Comment;
51 changes: 51 additions & 0 deletions src/app/components/common/form/TextareaSelectedField.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import React from "react";
import PropTypes from "prop-types";

const TextareaSelectedField = ({
label,
type,
name,
value,
onChange,
error
}) => {
const handleChange = ({ target }) => {
onChange({ name: target.name, value: target.value });
};

const getInputClasses = () => {
return "form-control " + (error ? "is-invalid" : "");
};

return (
<div className="mb-4">
<label htmlFor={name}>{label}</label>
<div className="input-group has-validation">
<textarea
type={type}
id={name}
name={name}
value={value}
onChange={handleChange}
// className="form-control"
className={getInputClasses()}
></textarea>
{error && <div className="invalid-feedback">{error}</div>}
</div>
</div>
);
};
TextareaSelectedField.defaultProps = {
type: "text"
};
TextareaSelectedField.propTypes = {
label: PropTypes.string,
type: PropTypes.string,
name: PropTypes.string,
value: PropTypes.string,
onChange: PropTypes.func,
error: PropTypes.string,
rows: PropTypes.string
};

export default TextareaSelectedField;
1 change: 1 addition & 0 deletions src/app/components/common/form/selectField.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const SelectField = ({
}) => {
const handleChange = ({ target }) => {
onChange({ name: target.name, value: target.value });
console.log(options);
};
const getInputClasses = () => {
return "form-select" + (error ? " is-invalid" : "");
Expand Down
3 changes: 3 additions & 0 deletions src/app/components/page/editUserPage/editUserPage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import MultiSelectField from "../../common/form/multiSelectField";
import SelectField from "../../common/form/selectField";
import TextField from "../../common/form/textField";
import { useHistory } from "react-router-dom";
import BackHistoryButton from "../../common/BackButton";

const EditUserPage = ({ userId }) => {
const history = useHistory();
Expand Down Expand Up @@ -154,8 +155,10 @@ const EditUserPage = ({ userId }) => {

return (
<>
{/* <div className="mx-5 mr-5"></div> */}
{loading === false ? (
<div className="container mt-5 ">
<BackHistoryButton />
<div className="row">
<div className="col-md-6 offset-md-3 shadow p-4">
<form onSubmit={handleSubmit}>
Expand Down
Loading