How can I use redux API call to avoid this error? - javascript

This is my Apı request file. I designed like that.
import { createApi, fetchBaseQuery } from "#reduxjs/toolkit/query/react";
// DEV ONLY!!!
const pause = (duration) => {
return new Promise((resolve) => {
setTimeout(resolve, duration);
});
};
const usersApi = createApi({
reducerPath: "users",
baseQuery: fetchBaseQuery({
baseUrl: "http://127.0.0.1:4000/",
fetchFn: async (...args) => {
// REMOVE FOR PRODUCTION
await pause(3000);
return fetch(...args);
},
}),
endpoints(builder) {
return {
addUser: builder.mutation({
query: (token, user) => {
return {
url: "/users",
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
},
body: {
role: user.role,
firmId: user.firmId,
firmName: user.firmName,
name: user.name,
lastName: user.lastName,
email: user.email,
tel: user.tel,
isActive: user.isActive,
},
invalidates: ["fetchUser"],
provides: ["fetchUser"],
};
},
}),
getUser: builder.mutation({
query: (token, id) => {
return {
url: `/users/${id}`,
method: "GET",
headers: {
Authorization: `Bearer ${token}`,
},
};
},
}),
updateUser: builder.query({
query: (token, user) => {
return {
url: `/users/${user.id}`,
method: "PATCH",
headers: {
Authorization: `Bearer ${token}`,
},
body: {
role: user.role,
firmId: user.firmId,
firmName: user.firmName,
name: user.name,
lastName: user.lastName,
email: user.email,
tel: user.tel,
isActive: user.isActive,
},
invalidates: ["fetchUser"],
provides: ["fetchUser"],
};
},
}),
fetchUser: builder.query({
query: (token) => {
return {
url: "/users",
method: "GET",
headers: {
Authorization: `Bearer ${token}`,
},
};
},
}),
};
},
});
export const {
useFetchUserQuery,
useAddUserMutation,
useGetUserQuery,
useUpdateUserMutation,
} = usersApi;
export { usersApi };
I import my api file in here. Export api functions as below of my code.
import { configureStore } from "#reduxjs/toolkit";
import { setupListeners } from "#reduxjs/toolkit/query";
import { devicesApi } from "./devicesApi";
import { deviceTypeApi } from "./deviceTypeApi";
import { deviceStatusApi } from "./deviceStatusApi";
import { usersApi } from "./usersApi";
import { cityApi } from "./cityApi";
import { townApi } from "./townApi";
import {
deviceFormReducer,
changeDeviceTypeId,
changeDeviceTypeName,
changeFirmId,
changeIp,
changeImei,
changeSerialNo,
changeUserPassword,
changeAdminPassword,
changeConnectionLevel,
changeQuota,
changeCounter,
changeDeviceStatusId,
changeDeviceStatusName,
changeIsActive,
changeNote,
} from "./slices/deviceForm";
export const store = configureStore({
reducer: {
form: deviceFormReducer,
[townApi.reducerPath]: townApi.reducer,
[cityApi.reducerPath]: cityApi.reducer,
[devicesApi.reducerPath]: devicesApi.reducer,
[deviceTypeApi.reducerPath]: deviceTypeApi.reducer,
[deviceStatusApi.reducerPath]: deviceStatusApi.reducer,
[usersApi.reducerPath]: usersApi.reducer,
},
middleware: (getDefaultMiddleware) => {
return getDefaultMiddleware()
.concat(usersApi.middleware)
.concat(devicesApi.middleware)
.concat(deviceTypeApi.middleware)
.concat(townApi.middleware)
.concat(cityApi.middleware)
.concat(deviceStatusApi.middleware);
},
});
setupListeners(store.dispatch);
export {
changeDeviceTypeId,
changeDeviceTypeName,
changeFirmId,
changeIp,
changeImei,
changeSerialNo,
changeUserPassword,
changeAdminPassword,
changeConnectionLevel,
changeQuota,
changeCounter,
changeDeviceStatusId,
changeDeviceStatusName,
changeIsActive,
changeNote,
};
export {
useFetchDevicesQuery,
useAddDeviceMutation,
useGetDeviceByIdQuery,
useGetDeviceByIpQuery,
useRemoveDeviceMutation,
} from "./devicesApi";
export {
useFetchUserQuery,
useAddUserMutation,
useGetUserQuery,
useUpdateUserMutation,
} from "./usersApi";
export { useFetchCityQuery } from "./cityApi";
export { useFetchTownQuery } from "./townApi";
export { useFetchDeviceStatusQuery } from "./deviceStatusApi";
export { useFetchDeviceTypeQuery } from "./deviceTypeApi";
This is my code. In here I want to update my user but I am gettin error about the usage "const [updateUser, { isLoading }] = useUpdateUserMutation();".
I am getting this error I tried something , I am newly person in react. Please help about what is my problem ?
import { useUpdateUserMutation } from "../../store";
import { useState, useEffect } from "react";
import Dropdown from "../../components/DropDown";
import { MdUpdate } from "react-icons/md";
import { AiOutlineSave } from "react-icons/ai";
import { TbReportAnalytics, TbReportMedical } from "react-icons/tb";
import { ImCross } from "react-icons/im";
import { GiConfirmed, GiCancel } from "react-icons/gi";
import useAuth from "../../hooks/useAuth";
function EditUserModals({ onClose, onClick, user }) {
const [showConfirmModal, setShowConfirmModal] = useState(false);
const [Info, setInfo] = useState(0);
const [input, setInput] = useState(user);
const { auth } = useAuth();
const token = auth.accessToken;
const [updateUser, { isLoading }] = useUpdateUserMutation();
const HandleOpenModal = (e) => {
e.preventDefault();
if (input.role !== "" && input.firmId !== "") {
setShowConfirmModal(true);
}
};
useEffect(() => {
if (Info === 0) setInput(user);
}, [Info]);
const handleCloseModel = (bool) => {
if (bool) {
onClick();
} else {
setShowConfirmModal(false);
}
};
const userRoles = [
{ label: "Admin", value: "admin" },
{ label: "User", value: "user" },
];
const firmIds = [{ label: "Bayıner", value: "Bayıner" }];
const handleSelectFirmName = (option) => {
//Firma ID atılacak
setInput({
...input,
firmName: option.value,
firmId: 1,
});
};
const handleSelectUserRoles = (option) => {
setInput({ ...input, role: option.value });
};
return (
<div className="fixed w-screen h-screen top-0 left-0 z-30 bg-white">
{/*
Confirm Modal
*/}
<div
className={`z-50 flex items-center justify-center absolute ${
showConfirmModal ? "flex" : "hidden"
} w-full h-full bg-opacity-50 transition-all duration-100`}
>
<div
onClick={() => handleCloseModel(false)}
className="fixed inset-0 bg-gray-300 opacity-80 "
></div>
<div className=" flex z-10 flex-col gap-3 bg-slate-600 mx-auto w-fit p-1 rounded-xl ">
<div className="bg-white rounded-xl p-4 flex flex-col items-center">
<p className="mb-4 flex flex-col gap-2">
<p>İsim: {input.name}</p>
<p>Soysim: {input.lastName}</p> <p>Email: {input.email}</p>
<p>Firma: {input.firmName}</p>
<p>Telefon: {input.tel}</p>
bilgilerine sahip kullanıcıyı oluşturmak istiyor musunuz?
</p>
<div className="flex gap-2">
<button
onClick={() => handleCloseModel(true)}
className="flex items-center bg-slate-800 text-white p-2 rounded-xl border-4
hover:bg-white hover:border-slate-800 hover:text-slate-800"
>
<GiConfirmed />
Onay
</button>
<button
onClick={() => handleCloseModel(false)}
className="flex items-center bg-white border-4 rounded-xl p-2 hover:bg-slate-600 hover:text-white"
>
<GiCancel />
İptal
</button>
</div>
</div>
</div>
</div>
{/*
Top Absolute Information
*/}
<div className="absolute top-0 bg-primary z-10 w-full flex justify-between h-fit">
<div className="flex">
<button
onClick={() => setInfo(0)}
className={`${
Info === 0 ? "bg-white border-primary " : "bg-fourth text-white"
} flex px-6 py-3 z-20 transition-all duration-500
hover:bg-white hover:text-fourth gap-4`}
>
<div className="flex justify-center items-center pt-2">
<MdUpdate className="mr-2 w-6 h-6 " />
<p className=" ">Kullanıcı Düzenleme</p>
</div>
</button>
<button
onClick={() => {
//getDeviceByIp(device.ip);
setInfo(1);
}}
className={`${
Info === 1 ? "bg-white border-primary " : "bg-fourth text-white"
} flex px-6 py-3 z-20 transition-all duration-500
hover:bg-white hover:text-fourth gap-4`}
>
<div className="flex justify-center items-center pt-2">
<TbReportAnalytics className="mx-4 w-6 h-6 " />
<p className=" ">Rapor Ekle</p>
</div>
</button>
</div>
<button
onClick={onClose}
className={`flex px-8 py-2 transition-all duration-200 text-fourth
h-14 z-10 justify-center items-center
hover:text-fifth w-fit `}
>
<ImCross className="w-6 h-6 " />
</button>
</div>
<form
onSubmit={HandleOpenModal}
className={` grid-flow-row w-full h-full z-0 text-sm px-32 ${
Info === 0 ? "grid" : "hidden"
} `}
>
</form>
<form
onSubmit={HandleOpenModal}
className={` grid-flow-row w-full h-full z-0 text-sm px-32 ${
Info === 1 ? "grid" : "hidden"
} `}
>
<div className="grid sm:grid-cols-2 grid-cols-1 gap-6 overflow-scroll mt-24 mb-16">
<button className="h-fit items-center text-fourth flex bg-secondary rounded-br-2xl rounded-tl-2xl px-6 py-3 active:bg-primary hover:bg-third transition-all duration-500">
<TbReportMedical />
<p>Rapor Ekle</p>
</button>
<Dropdown
options={firmIds}
value={{
label: input.firmName,
value: input.firmName,
}}
onChange={handleSelectFirmName}
search={true}
barValue={"-Raporlar-"}
/>
</div>
</form>
<div className="fixed bottom-0 ">
<div
style={{ height: "70px" }}
className="w-screen bg-primary flex justify-center items-center"
></div>
</div>
</div>
);
}
export default EditUserModals;
This error that I am gettin in browser
The above error occurred in the <EditUserModals> component:
at EditUserModals (http://localhost:3000/static/js/bundle.js:3467:5)
at div
at UsersPage (http://localhost:3000/static/js/bundle.js:9828:65)
at RenderedRoute (http://localhost:3000/static/js/bundle.js:578653:5)
at Outlet (http://localhost:3000/static/js/bundle.js:579034:26)
at RequireAuth (http://localhost:3000/static/js/bundle.js:5039:5)
at RenderedRoute (http://localhost:3000/static/js/bundle.js:578653:5)
at Outlet (http://localhost:3000/static/js/bundle.js:579034:26)
at div
at div
at div
at SiteLayout (http://localhost:3000/static/js/bundle.js:5750:74)
at RenderedRoute (http://localhost:3000/static/js/bundle.js:578653:5)
at Routes (http://localhost:3000/static/js/bundle.js:579119:5)
at App
at RenderedRoute (http://localhost:3000/static/js/bundle.js:578653:5)
at Routes (http://localhost:3000/static/js/bundle.js:579119:5)
at AuthProvider (http://localhost:3000/static/js/bundle.js:6940:5)
at NavigationProvider (http://localhost:3000/static/js/bundle.js:7026:5)
at UsersProvider (http://localhost:3000/static/js/bundle.js:7125:5)
at Provider (http://localhost:3000/static/js/bundle.js:573644:5)
at Router (http://localhost:3000/static/js/bundle.js:579057:15)
at BrowserRouter (http://localhost:3000/static/js/bundle.js:577259:5)
Consider adding an error boundary to your tree to customize error handling behavior.
Visit https://reactjs.org/link/error-boundaries to learn more about error boundaries.
overrideMethod # react_devtools_backend.js:4012
logCapturedError # react-dom.development.js:18687
update.callback # react-dom.development.js:18720
callCallback # react-dom.development.js:13923
commitUpdateQueue # react-dom.development.js:13944
commitLayoutEffectOnFiber # react-dom.development.js:23391
commitLayoutMountEffects_complete # react-dom.development.js:24688
commitLayoutEffects_begin # react-dom.development.js:24674
commitLayoutEffects # react-dom.development.js:24612
commitRootImpl # react-dom.development.js:26823
commitRoot # react-dom.development.js:26682
performSyncWorkOnRoot # react-dom.development.js:26117
flushSyncCallbacks # react-dom.development.js:12042
(anonymous) # react-dom.development.js:25651
``

Related

I want to pass a function to the active state and a different function to inactive state in react

function Product(props) {
const [Shop, setShop] = useState(false);
const Shopped = () => setShop(!Shop);
return(
<section onClick={() => { Shopped();}} >
{!Shop ? (
<FaShoppingCart
title="افزودن به سبد خرید"
className="absolute right-0 m-4 cursor-pointer hover:text-green-700"
/>) :
(<FaShoppingCart className="absolute right-0 m-4 cursor-pointer text-green-700" />
)}
</section>
)}
export default Product
I want to pass addToCart() function to shop when its inactive. and pass removeFromCart() function when its active in react.
You can create this prop with a condition:
<FaShoppingCart
...
onClick={Shop ? removeFromCart : addToCart}
/>
You can provide one function and change the functionality based on your Shop state.
function Product(props) {
const [Shop, setShop] = useState(false);
const Shopped = () => setShop(!Shop);
const handleIconClick = () => {
if (Shop === true) {
removeFromCart();
} else {
addToCart();
}
};
return (
<section
onClick={() => {
Shopped();
}}
>
{!Shop ? (
<FaShoppingCart
title="افزودن به سبد خرید"
className="absolute right-0 m-4 cursor-pointer hover:text-green-700"
onClick={handleIconClick}
/>
) : (
<FaShoppingCart
className="absolute right-0 m-4 cursor-pointer text-green-700"
onClick={handleIconClick}
/>
)}
</section>
);
}

why emeded video just show html tags in react after sending body with markdown editor

why emeded video just show html tags in react after sending body with markdown editor
why every things shows ok in markdown editor and embedded video showing correctly but when sending to the server it just shows html tags
see these pictures for me it is ok when u want write in editor
but after u post it just show that plaintext html tags
i mean in preview mode is ok showing the video but after sending body to server . this just showing plain text or html tags
can u see pictures
this picture is when posting
https://postimg.cc/VSJQr1NR
and this after posting just plain html tag in website
https://postimg.cc/K1vybtSC
https://i.postimg.cc/NFy2YHQy/333.png
https://i.postimg.cc/4NW4wdGq/ccc.png
should I use npm package and install in the backend file post.js ?
why backend server does not recognize the embedded video code but in markdown editor everything is showing correctly
this is dev.to clone and people come to website using markdown editor and then post . but embeded video is not showing . just html tags like picture what is wrong with my code ?
this is my new-post.jsx file when people try to post
// import { createEditor } from 'slate'
// import { Slate, Editable, withReact } from 'slate-react'
// import "easymde/dist/easymde.min.css";
// import React, { Component } from 'react';
import { rehype } from 'rehype';
import rehypeVideo from 'rehype-video';
import MDEditor from '#uiw/react-md-editor';
// import { useMemo } from "react";
// import SlateEditor from "./Editorr";
// import React, { useState, useRef } from "react";
import './NewPost.css'
// import SimpleMDE from "react-simplemde-editor";
import { useContext, useEffect, useRef, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useNavigate } from 'react-router-dom';
import tw from 'twin.macro';
import Error from '../../common/Error';
import LoadingSpinner from '../../common/LoadingSpinner';
import RouteWrapper from '../../common/RouteWrapper';
import socketContext from '../../context/SocketContext';
import { selectCurrentUser } from '../../core/features/auth/authSlice';
import { useCreatePostMutation } from '../../core/features/posts/postsApiSlice';
import { useGetUserDashboardQuery } from '../../core/features/users/usersApiSlice';
import useBase64 from '../../hooks/useBase64';
import useRequireAuth from '../../hooks/useRequireAuth';
import { useMemo } from "react";
// import Appp from "./Editorr";
// import { Editor } from "react-draft-wysiwyg";
// import "../../../node_modules/react-draft-wysiwyg/dist/react-draft-wysiwyg.css";
// import React, { Component } from 'react';
// import "../NewPost/react-draft-wysiwyg.css"
// import "react-draft-wysiwyg/dist/react-draft-wysiwyg.cs";
// import LiveMarkdown from '../markdowneditor/markdowneditor';
// import EasyMDE from 'easymde';
// const [editor] = useState(() => withReact(createEditor()))
const NewPost = () => {
// const JoditEditor = {
// "defaultFontSizePoints": "pt",
// "uploader": {
// "insertImageAsBase64URI": true
// },
// "language": "fa",
// "toolbarButtonSize": "large",
// "defaultMode": "1",
// "minHeight": 400,
// "inline": true,
// "toolbarInlineForSelection": true,
// "showPlaceholder": false,
// "buttons": "bold,italic,underline,strikethrough,eraser,ul,ol,font,fontsize,paragraph,classSpan,lineHeight,superscript,subscript,file,image,video,speechRecognize,spellcheck"
// };
// const editor = useRef(null);
// const config = useMemo ({
// readonly: false,
// height: 400,
// });
// const handleUpdate = (event) => {
// const editorContent = event.target.innerHTML;
// setBody(setBody);
// };
const [title, setTitle] = useState('');
const [file, setFile] = useState('');
// const [editorstate, setEditorstate] = useState('');
const [body, setBody] = useState('');
const [tags, setTags] = useState('');
const [isTagsFocused, setIsTagsFocused] = useState(false);
const [inputsFilled, setInputsFilled] = useState(false);
const filePickerRef = useRef();
const titleRef = useRef();
const [createPost, { isLoading, isError }] = useCreatePostMutation();
const navigate = useNavigate();
const currentUser = useSelector(selectCurrentUser);
const dispatch = useDispatch();
const previewURL = useBase64(file);
const { isAuthed, handleAuth } = useRequireAuth();
const { socket } = useContext(socketContext);
const { data: user } = useGetUserDashboardQuery(currentUser.username);
useEffect(() => titleRef.current.focus(), []);
useEffect(() => {
if (title
// && file && body
&& tags) setInputsFilled(true);
else setInputsFilled(false);
}, [title, file, body, tags]);
const handleSubmit = async () => {
if (inputsFilled) {
if (isAuthed) {
try {
const { id } = await createPost({
title,
file: previewURL,
body,
tags,
authorUsername: currentUser.username,
}).unwrap();
socket.emit('post', {
sender: currentUser,
receivers: user?.followers,
post: { title, id },
});
setTitle('');
setFile('');
setBody('');
setTags('');
navigate('/');
} catch (err) {
console.log(err);
}
} else handleAuth();
}
};
return (
<RouteWrapper>
<Wrapper>
{isLoading && <LoadingSpinner />}
{!isLoading && (
<NewPostWrapper>
<Heading>ایجاد پست جدید</Heading>
<InputWrapper>
<Label dir='rtl' htmlFor='title'>موضوع <p> دقت داشته باشید که موضوع بیشتر از 48 حرف نمیتواند باشد </p></Label>
<Input
maxLength={48}
type="text"
dir='rtl'
ref={titleRef}
id='title'
value={title}
onBlur={e => setTitle(prev => prev.trim())}
onChange={e => setTitle(e.target.value)}
required
/>
<br></br> <Label dir='rtl' htmlFor='title' ><p> عکس برای پست تان انتخاب نمایید . انتخاب عکس اجباری نمی باشد</p> </Label>
</InputWrapper>
<InputWrapper>
<Input
type='file'
ref={filePickerRef}
onChange={e => setFile(e.target.files[0])}
style={{ display: 'none' }}
/>
<ImagePreview src={previewURL.toString()} alt='' />
<Button onClick={() => filePickerRef.current.click()}>انتخاب عکس</Button>
</InputWrapper>
{/* <p>متن خود را وارد نمایید <br /> برای اضافه کردن کد جاوااسکریپت به متن بدین شکل عمل کنید <br />
javascript
<br />محل قرار گیری کد جاوا اسکریپتی شما <br/>
</p>*/}
<InputWrapper2>
{/* 1 */}
{/* <SimpleMDE value={body} onChange={setBody} required /> */}
{/* 2 */}
{/* <Editor
value={body}
// editorState={}
toolbarClassName="toolbarClassName"
wrapperClassName="wrapperClassName"
editorClassName="editorClassName"
onEditorStateChange={setBody}
textAlignment="right"
placeholder="اینجا تایپ کنید"
/>; */}
{/* 3 */}
<div className="md-editor-rtl ">
<MDEditor
value={body}
style={{ padding: 15 }}
linkTarget="_blank"
onChange={setBody}
height={400}
rehypePlugins={[[rehypeVideo]]}
textareaProps={{
placeholder: "اینجا تایپ کنید",
}}
/>
</div>
<p style={{ "color": "gray", "fontSize": "0.8rem" }}> راهنما : در سمت چپ پیش نمایش پست خودتان را میتوانید ببینید . هنگام نوشتن کدهای برنامه نویسی ملاک سمت چپ میباشد. همچنین برای اضافه کردن کد به متن ابتدا کد خود را درون یک ویرایشگر متن مانند Vs Code نوشته و سپس به شکل زیر درون ادیتور بالا پیست کنید <br /> <br /> ```javascript
<br /> محل قرار گیری کد شما <br />
```</p> {/* */}
{/* <SlateEditor /> */}
{/* <JoditEditor
ref={editor}
value={body}
config={config}
// onBlur={handleSubmit}
handleSubmit={handleSubmit}
onChange={setBody}
required
/> */}
{/* <div dangerouslySetInnerHTML={{ __html: body }} /> */}
</InputWrapper2>
<InputWrapper>
<Label htmlFor='tags'>
تگ ها
{isTagsFocused && (
<Span>تگ ها را با کاما(,) از یکدیگر جدا کنید </Span>
)}
</Label>
<Input
maxLength={15}
id='tags'
value={tags}
onFocus={() => setIsTagsFocused(true)}
onBlur={() => setIsTagsFocused(false)}
onChange={e => setTags(e.target.value.replace(/ /g, ''))}
required
/>
</InputWrapper>
<Submit onClick={handleSubmit}>تایید</Submit>
{isError && <Error>خطاا در انجام عملیات . دوباره امتحان کنید . زمان کامپیوتر خود رابررسی کنید و فقط از آی پی ایران اقدام به ارسال پست بکنید </Error>}
{!inputsFilled && <Error>تمام فیلدها اجباری هست . زمان تقریبی ارسال پست یک دقیقه میباشد . لطفا صبور باشید عکس پست تان آپلود شود </Error>}
</NewPostWrapper>
)}
</Wrapper>
</RouteWrapper>
);
};
const Submit = tw.button`bg-lighter-gray hover:bg-light-gray rounded-md text-center py-2 px-1 w-full text-sm`;
const ImagePreview = tw.img`w-32 h-32 mx-auto border border-gray flex justify-center items-center text-center object-cover`;
const Input = tw.input`py-1 px-2 rounded-md outline-none border-2 border-solid border-gray focus:border-blue`;
const Label = tw.label`font-bold text-dark-gray`;
const Span = tw.p`inline ml-sm`;
const InputWrapper = tw.div`flex flex-col gap-2 `;
const Button = tw.button`bg-lighter-gray hover:bg-light-gray rounded-md text-center py-2 px-1 w-28 text-sm mx-auto`;
const Heading = tw.h1`text-dark-gray text-center`;
const NewPostWrapper = tw.div`bg-white w-3/5 mob:(w-full px-4) mx-auto py-20 px-8 [&>*:not(:last-child)]:mb-md`;
const Wrapper = tw.div`flex items-center`;
const InputWrapper2 = tw.div`border border-gray`;
export default NewPost;
and this is my post list file
import { useEffect } from 'react';
import { AiOutlineHeart } from 'react-icons/ai';
import { BsBookmark, BsBookmarkFill } from 'react-icons/bs';
import { MdOutlineModeComment } from 'react-icons/md';
import { useNavigate } from 'react-router-dom';
import tw, { styled, theme } from 'twin.macro';
import { createPostUrl, formatDate } from '../../../helpers/string';
import { calcReadingTime } from '../../../helpers/utils';
import useBreakpoint from '../../../hooks/useBreakpoint';
import usePostReaction from '../../../hooks/usePostReaction';
import useRequireAuth from '../../../hooks/useRequireAuth';
import LoadingController from '../../LoadingController/LoadingController';
import Tags from '../../Tags';
const Post = ({ post, isFirstPost, filteredTag, toInvalidate }) => {
const navigate = useNavigate();
const isSmall = useBreakpoint(theme`screens.sm.max`.replace('px', ''));
const { isAuthed, handleAuth } = useRequireAuth(false);
const { id, author, likes, unicorns, bookmarks } = post;
const likesArr = [...likes];
const unicornsArr = [...unicorns];
const bookmarksArr = [...bookmarks];
const { state, handleReaction, isLoading } = usePostReaction(
id,
author,
likesArr,
unicornsArr,
bookmarksArr,
post.title,
toInvalidate
);
const { isBookmarked } = state;
const handleSave = () => {
const action = isBookmarked ? 'removeBookmark' : 'bookmark';
const effect = isBookmarked ? 'negative' : 'positive';
if (isAuthed) handleReaction(action, effect, bookmarksArr, 'isBookmarked');
else handleAuth();
};
return (
post && (
<Wrapper>
{/* {isFirstPost && (
<Image
onClick={() =>
navigate(`/${post.author?.username}/${createPostUrl(post.title, post.id)}`)
}
src={post?.image?.url}
/>
)} */}
<Content>
<Header onClick={() => navigate(`/${post?.author.username}`)}>
<Author src={post.author?.picture?.url} />
<AuthorMeta>
<AuthorName>{post.author?.name}</AuthorName>
<CreatedAt>{formatDate(post.createdAt)}</CreatedAt>
{formatDate(post.updatedAt) !== formatDate(post.createdAt) && (
<UpdatedAt>{`Updated ${formatDate(post.updatedAt)}`}</UpdatedAt>
)}
</AuthorMeta>
</Header>
<Title
onClick={() =>
navigate(`/${post.author.username}/${createPostUrl(post.title, post.id)}`)
}>
{post.title}
</Title>
<Tags tags={post.tags} filteredTag={filteredTag} />
<Footer>
<Reactions
onClick={() =>
navigate(`/${post.author.username}/${createPostUrl(post.title, post.id)}`)
}>
<SumOfReactions>
<HeartIcon>
<AiOutlineHeart />
</HeartIcon>
<Total>
{isSmall
? post.likes.length + post.unicorns.length + post.bookmarks.length
: `${
post.likes.length + post.unicorns.length + post.bookmarks.length
} لایک`}
</Total>
</SumOfReactions>
<SumOfComments>
<CommentIcon>
<MdOutlineModeComment />
</CommentIcon>
<Total>
{isSmall ? post.comments?.length : `${post.comments?.length} کامنت ها`}
</Total>
</SumOfComments>
</Reactions>
<Other>
<MinutesRead>
{calcReadingTime(post.body)} {`دقیقه ${!isSmall ? 'زمان خواندن' : ''}`}
</MinutesRead>
<LoadingController isLoading={isLoading}>
<SaveButton onClick={handleSave} isBookmarked={isBookmarked}>
{isBookmarked ? <BsBookmarkFill /> : <BsBookmark />}
</SaveButton>
</LoadingController>
</Other>
</Footer>
</Content>
</Wrapper>
)
);
};
const Image = styled.img`
width: 100%;
height: 450px;
object-fit: cover;
cursor: pointer;
`;
const Content = tw.div`px-sm py-md`;
const Header = tw.div`flex justify-between items-center w-max gap-sm mb-2`;
const Author = tw.img`w-12 h-12 rounded-full cursor-pointer`;
const AuthorMeta = tw.div``;
const AuthorName = tw.h4`text-darker-gray pr-1 pt-1 rounded-md hover:bg-lighter-gray cursor-pointer`;
const CreatedAt = tw.p`text-darker-gray`;
const UpdatedAt = tw.p`text-darker-gray`;
const Title = tw.h2`mb-2 hover:text-blue cursor-pointer`;
const Footer = tw.div`flex justify-between items-center`;
const Reactions = tw.div`flex justify-between items-center gap-md`;
const SumOfReactions = tw.div`flex justify-between items-center gap-2 text-darker-gray rounded-md px-2 py-1 hover:bg-lighter-gray cursor-pointer`;
const HeartIcon = styled.div`
svg {
font-size: 1.5rem;
}
`;
const SumOfComments = tw.div`flex justify-between items-center gap-2 text-darker-gray rounded-md px-2 py-1 hover:bg-lighter-gray cursor-pointer`;
const CommentIcon = styled.div`
svg {
font-size: 1.5rem;
}
`;
const Total = tw.p``;
const Other = tw.div`flex justify-between items-center gap-2`;
const MinutesRead = tw.p`text-darker-gray`;
const SaveButton = styled.button`
${tw`p-2 border text-lg border-solid border-transparent rounded-md hover:(text-blue bg-light-blue)`}
${({ isBookmarked }) => isBookmarked && tw`bg-light-gray`}
`;
const Wrapper = styled.div`
${tw`rounded-lg w-full overflow-hidden bg-white mb-2 shadow-sm hover:shadow`}
`;
export default Post;
sorry for bad english . I just want answer . can not understand why website does not recognize embedded video code like mde editor
and this is my post.body
import { useNavigate } from 'react-router-dom';
import tw, { styled } from 'twin.macro';
import AuthorDetails from '../../../common/AuthorDetails';
import CustomMarkdown from '../../../common/CustomMarkdown';
import Tags from '../../../common/Tags';
import { formatDate } from '../../../helpers/string';
import Advertise from './Advertise';
import Comments from './Comments';
import './Post.css';
const Post = ({ post, isLaptop }) => {
const navigate = useNavigate();
return (
<Wrapper>
<Image src={post?.image?.url}
/>
{/* <div id="pos-article-display-78271"></div> */}
<Advertise />
<Content>
<Header>
<Author
src={post.author.picture.url}
onClick={() => navigate(`/${post.author.username}`)}
/>
<AuthorMeta>
<AuthorName>{post.author.name}</AuthorName>
<CreatedAt>{formatDate(post.createdAt)}</CreatedAt>
{formatDate(post.updatedAt) !== formatDate(post.createdAt) && (
<UpdatedAt>{`Updated ${formatDate(post.updatedAt)}`}</UpdatedAt>
)}
</AuthorMeta>
</Header>
<Title>{post.title}</Title>
<Tags tags={post.tags} isColored={true} />
<div className="postbody"> <PostBody>
<iframe> <CustomMarkdown children={post.body} /></iframe>
</PostBody></div>
<CommentsContainer>
{post.comments && (
<Comments postTitle={post.title} postAuthor={post.author} postId={post.id} />
)}
</CommentsContainer>
</Content>
{isLaptop && <AuthorDetails post={post} />}
</Wrapper>
);
};
const Image = styled.img`
width: 100%;
height: 100%;
margin: 0 auto;
object-fit: contain;
cursor: pointer;
`;
const Header = tw.div`flex justify-between items-center w-max gap-sm mt-sm`;
const Author = tw.img`w-12 h-12 rounded-full cursor-pointer`;
const AuthorMeta = tw.div``;
const AuthorName = tw.h4`text-darker-gray pr-1 pt-1 rounded-md hover:bg-lighter-gray cursor-pointer`;
const CreatedAt = tw.p`text-darker-gray`;
const UpdatedAt = tw.p`text-darker-gray`;
const Title = tw.h1`my-sm`;
const PostBody = tw.div`mt-md pb-md border-b border-light-gray border-solid`;
const CommentsContainer = styled.div`
> *:not(:first-child) {
${tw`mt-sm`}
}
${tw`mt-md`}
`;
const Content = tw.div`px-lg my-lg mob:(px-sm)`;
const Wrapper = tw.div`w-full h-full rounded-md overflow-hidden bg-white shadow`;
export default Post;

File upload in React-Hook-Form returns empty object upon submission

I am trying to submit the form using the react-hook form. But it always returns empty data.
The Request payload returns something like this in the browser
{nameOnCurrentLicense: "test Biden",
driversLicenseNumber: "dfghj3243546",
deliveryAddress: "vbn 456 fghjgfs, UK",
driversLicenseNumber: "dfghj3243546",
driversLicensePhoto: {0: {}},
driversLicensePricingId: 1,
nameOnCurrentLicense: "test Biden",
passportPhoto: {0: {}}
}
import { data } from 'autoprefixer';
import { useEffect, useRef, useState } from 'react';
import { useForm } from 'react-hook-form';
import { Link } from 'react-router-dom';
import { toast } from 'react-toastify';
import {
Button,
Container,
FileInput,
Input,
Line,
Radio,
TextInput,
Typography,
} from '../../../../common/components';
import { axiosInstance } from '../../../../config/axiosInstance';
import { createFormData } from '../../../../helpers';
import { useAppDispatch, useAppSelector } from '../../../../hooks';
import {
useDriverLicenseMutation,
useDriverLicensePayCardMutation,
useDriverLicensePayWalletMutation,
} from '../../apis';
import { formTwo } from '../../apis/slice/FormSlice';
import { formProps } from '../../types';
import { DriverLicenseSubmitPayload } from './types';
function Drift() {
const [price, setPrice] = useState([]);
const [passportFile, setPassportFile] = useState(null);
const [licenseFile, setLicenseFile] = useState(null);
const [driversLicensePricingId, setDriversLicensePricingId] = useState('');
// api hooks
const [onDriverLicense, { isLoading }] = useDriverLicenseMutation();
const [onInitPaymentViaWallet, { isLoading: isInitiatingWallet }] =
useDriverLicensePayWalletMutation();
const [onInitPaymentViaCard, { isLoading: isInitiatingCard }] = useDriverLicensePayCardMutation();
//RHF context
const priceSelection = useAppSelector((state) => state.formAction.FormTwo);
const { register, handleSubmit, errors } = useForm({
defaultValues: {
nameOnCurrentLicense: data.nameOnCurrentLicense,
driversLicenseNumber: data.driversLicenseNumber,
deliveryAddress: data.deliveryAddress,
passportPhoto: data.passportPhoto,
driversLicensePricingId: Number(priceSelection.id),
driversLicensePhoto: data.driversLicensePhoto,
},
mode: 'onBlur',
// resolver: yupResolver(schema),
});
//submit handler
const onSubmitForm = async (data) => {
try {
let result = await onDriverLicense({
nameOnCurrentLicense: data.nameOnCurrentLicense,
driversLicenseNumber: data.driversLicenseNumber,
deliveryAddress: data.deliveryAddress,
passportPhoto: data.passportPhoto,
driversLicensePricingId: Number(priceSelection.id),
driversLicensePhoto: data.driversLicensePhoto,
}).unwrap();
result.success === true &&
toast.success(result.message, {
position: toast.POSITION.BOTTOM_RIGHT,
});
} catch (error) {
console.log('This is the error', error);
}
};
useEffect(() => {
axiosInstance
.get('drivers-license/pricing')
.then((response) => {
setPrice(response.data.data);
})
.catch((error) => console.log(error));
return () => {};
}, []);
const dispatch = useAppDispatch();
//form field
const personalInputs = [
{ name: 'nameOnCurrentLicense', type: 'text', label: 'Name on current License' },
{ name: 'driversLicenseNumber', type: 'text', label: "Driver's license number" },
{ name: 'deliveryAddress', type: 'text', label: 'Delivery address' },
];
return (
<Container containerStyle='py-12'>
<form onSubmit={handleSubmit(onSubmitForm)}>
<>
<div className='w-full flex md:flex-row flex-col justify-between items-start flex-wrap h-full'>
<div className=' w-full md:w-[55%] px-6 py-3'>
<Typography textStyle='text-md font-semibold'>Fill out your informations</Typography>
<Typography variant='label'>
We’ll require you to fill out some information before we get you started.
</Typography>
<Line variant='header' title='Personal Information' />
{personalInputs.map((item, index) => (
<TextInput
key={index}
{...register(`${item.name}`)}
id={item.name}
type='text'
label={item.label}
name={item.name}
// error={!!errors.item.name}
// helperText={errors?.field.name?.message}
/>
))}
<Line variant='header' title='Upload Document' />
<div className='flex justify-between items-center'>
<div className='w-[45%] pt-4'>
<input
{...register('passportPhoto')}
type='file'
name={'passportPhoto'}
accept='image/png, image/gif, image/jpeg'
/>
</div>
<div className='w-[45%] pt-4'>
<input
{...register('driversLicensePhoto')}
type='file'
name={'driversLicensePhoto'}
accept='image/png, image/gif, image/jpeg'
/>
</div>
</div>
</div>
<div className='w-full md:w-[45%] pl-0 lg:pl-6 pt-12 md:pt-0'>
<Typography variant='h6' textStyle='font-semibold text-center'>
Pricing / Years of Validity
</Typography>
<div className='pt-8'>
<Radio
ref={register}
name='driversLicensePricingI'
onChange={(e) => setDriversLicensePricingId(e.target.value)}
data={price}
/>
</div>
<div className='w-full bg-GRAY flex justify-between items-center p-8 rounded-xl'>
<Typography variant='h5' textStyle='font-semibold'>
Total cost
</Typography>
{priceSelection.amount !== undefined ? (
<Typography textStyle='text-3xl font-medium text-black'>{`₦ ${priceSelection.amount}`}</Typography>
) : (
<Typography textStyle='text-3xl font-medium text-black'>{`₦ 0.00`}</Typography>
)}
</div>
</div>
</div>
<div className='w-full md:w-[55%]'>
<div className='flex flex-row justify-end items-center w-full pt-16'>
<Link to='' className='font-medium text-xs lg:text-sm hover:text-opacity-50'>
Cancel
</Link>
<div className='w-40 ml-4'>
<Button
type='submit'
height={'h-10'}
variant='secondary'
containerButton=' w-full px-4 text-black'
text='Buy now'
/>
</div>
</div>
</div>
</>
</form>
</Container>
);
}
export default Drift;

How to use socket.on in react?

I am building a small chat app, but I have problems with receiving messages in react. The problem is that when I receive a message I setMessages, but at the same time the messages state gets cleared. The problem is problably that I don't know where to place socket.on, currently it's inside a useEffect hook.
export const Room = ({ socket }) => {
const [messages, setMessages] = useState([]);
const [input, setInput] = useState("");
const { id } = useParams();
useEffect(() => {
socket.emit("join room", id);
}, []);
useEffect(() => {
socket.on("message", (message) => {
setMessages([
...messages,
{ message: message, createdBy: "other", id: uuidv4() },
]);
});
}, []);
const sendMessage = () => {
console.log("send");
socket.emit("message", input);
setMessages([
...messages,
{ message: input, createdBy: "me", id: uuidv4() },
]);
};
console.log("foo");
return (
<div className="flex justify-center text-center">
<div className="w-screen h-screen px-2 max-w-4xl mt-10">
<p className="text-3xl">Code: {id}</p>
<div className="bg-white w-full h-3/4 rounded-xl border-2 border-black overflow-y-auto">
{messages.map((message) => (
<Message
text={message.message}
createdBy={message.createdBy}
key={message.id}
/>
))}
</div>
<div className="flex flex-row border-2 border-black mt-2 rounded-xl p-2 bg-white">
<input
className="flex-grow border-none focus:outline-none"
onInput={(e) => setInput(e.target.value)}
/>
<button
className=" bg-green-500 rounded-xl px-2 py-1"
onClick={sendMessage}
>
Send
</button>
</div>
</div>
</div>
);
};
I'm pretty sure you have a closure problem. messages is not what you think it is when it is run inside the useEffect -- it may not be the latest version.
It's safer and good practice to use the functional variant of the setter. This way you can be certain that messages is the current version:
setMessages(messages => [
...messages,
{ message: message, createdBy: "other", id: uuidv4() },
]);

Debounce Input while performing a query in `urql` GraphQL Client in React.js

I have a double slider like https://zillow.github.io/react-slider with min & max values. It calls a query when one of the sliders changes.
But since the query is huge, it takes a lot of time & I need to find a way to use debounce so that the query doesn't get called every so often.
I did find an excellent solution → https://stackoverflow.com/a/58594348/6141587 using just React.js but not sure how to use it with urql?
Home.tsx
import React from 'react'
import ReactSlider from 'react-slider'
import debounce from 'lodash.debounce'
import { AcquisitionList } from '../components/index'
const Home = () => {
const [price, setPrice] = React.useState([0, 1000000000])
const debounceSetPrice = React.useCallback(debounce(setPrice, 2000), [])
return (
<div className="h-full p-8 text-white bg-blue-gray-900">
<div className="flex items-center justify-center">
<div className="flex flex-col items-center text-white">
<span className="">Min</span>
<input
className="text-lg font-bold text-center min-w-16 rounded-xl bg-gradient-to-b from-indigo-700 bg-blue-gray-900"
name="minPrice"
type="text"
value={price[0]}
onChange={(e) => {
const minPrice = e.target.value
const maxPrice = price[1]
debounceSetPrice([minPrice, maxPrice])
}}
/>
</div>
<ReactSlider
step={1}
min={0}
max={1000000000}
className="w-1/2 h-5 pr-2 mx-8 my-4 rounded-md bg-blue-gray-700 cursor-grab"
thumbClassName="absolute w-8 h-8 cursor-[grab] rounded-full focus:outline-none focus:ring-2 focus:ring-offset-2 ring-offset-blue-gray-700 -top-1 bg-gradient-to-b from-indigo-700 bg-blue-gray-900 focus:ring-indigo-500 focus:border-indigo-500"
ariaLabel={['Min Price', 'Max Price']}
value={price}
onChange={(price) => {
debounceSetPrice(price)
}}
/>
<div className="flex flex-col items-center text-white">
<span className="">Max</span>
<input
className="text-lg font-bold text-center min-w-16 rounded-xl bg-gradient-to-b from-indigo-700 bg-blue-gray-900"
name="maxPrice"
type="text"
value={price[1]}
onChange={(e) => {
const minPrice = price[0]
const maxPrice = e.target.value
debounceSetPrice([minPrice, maxPrice])
}}
/>
</div>
</div>
<AcquisitionList minPrice={price[0]} maxPrice={price[1]} />
</div>
)
}
export default Home
AcquisitionsList.tsx
import React from 'react'
import { useQuery } from 'urql'
import { Card } from '../components/index'
import {
GET_ALL_ACQUISITIONS,
GET_ACQUISITIONS_BY_PRICE,
} from '../graphql/index'
export const AcquisitionList = ({ minPrice, maxPrice }) => {
const [result, reexecuteQuery] = useQuery({
query: GET_ALL_ACQUISITIONS,
variables: {
minPrice,
maxPrice,
skip: 10,
take: 10,
},
})
const { data, fetching, error } = result
if (fetching) return <p>Loading...</p>
if (error) return <p>Oh no... {error.message}</p>
return (
<div className="flex flex-wrap justify-center mt-10">
{data.getAllAcquisitions.map((startup, i) => {
return <Card key={i} startup={startup} index={i} />
})}
</div>
)
}
My current solution delays the slider values to change for 2 seconds which makes sense as I call debounceSetPrice directly. How do I go about solving this?
I found the solution thanks to URQL maintainer Jovi:
const Home = () => {
const priceRange = [0, 100000000000] // minPrice = 0, maxPrice = 100 billion
const timeout = React.useRef(null)
const [acquisitionPriceRange, setAcquisitionPriceRange] = React.useState(
priceRange
)
const [price, setPrice] = React.useState(priceRange)
React.useEffect(() => {
timeout.current = setTimeout(() => {
setAcquisitionPriceRange(price)
timeout.current = null
}, 2000)
return () => {
if (timeout.current) clearTimeout(timeout.current)
}
}, [price])
return (
<div className="h-full min-h-screen p-8 text-white bg-blue-gray-900">
.
.
.
<AcquisitionList
minPrice={acquisitionPriceRange[0]}
maxPrice={acquisitionPriceRange[1]}
undisclosed={enabled}
sortByPrice={sortByPrice}
sortByStartupName={sortByStartupName}
/>
</div>
)
}
export default Home
I set the value synchronously so the UI doesn't get delayed & queue up a debounce for the state I'm passing down in React.useEffect. I pass the same debounced state down to <AcquisitionList minPrice={acquisitionPriceRange[0]} maxPrice={acquisitionPriceRange[1]} />

Categories

Resources