feat: emojies

This commit is contained in:
IlyaDoronin 2023-09-21 13:07:30 +03:00
parent b7baa00a20
commit af59c764ed
11 changed files with 135 additions and 36 deletions

@ -17,6 +17,7 @@
"@types/react": "^18.0.0",
"@types/react-dnd": "^3.0.2",
"@types/react-dom": "^18.0.0",
"emoji-mart": "^5.5.2",
"file-saver": "^2.0.5",
"html-to-image": "^1.11.11",
"jszip": "^3.10.1",
@ -71,6 +72,8 @@
]
},
"devDependencies": {
"@emoji-mart/data": "^1.1.2",
"@emoji-mart/react": "^1.1.1",
"@types/react-beautiful-dnd": "^13.1.4",
"craco-alias": "^3.0.1"
}

@ -1,4 +1,4 @@
import { useState } from "react";
import { useState, useRef } from "react";
import { useParams } from "react-router-dom";
import { Draggable } from "react-beautiful-dnd";
import {
@ -7,29 +7,30 @@ import {
FormControl,
InputAdornment,
IconButton,
Popover,
useTheme,
useMediaQuery,
} from "@mui/material";
import { useDebouncedCallback } from "use-debounce";
import { EmojiPicker } from "@ui_kit/EmojiPicker";
import { questionStore, updateQuestionsList } from "@root/questions";
import PointsIcon from "@icons/questionsPage/PointsIcon";
import DeleteIcon from "@icons/questionsPage/deleteIcon";
import MessageIcon from "@icons/messagIcon";
import Popover from "@mui/material/Popover";
import TextareaAutosize from "@mui/base/TextareaAutosize";
import AddEmoji from "../../../assets/icons/questionsPage/addEmoji";
import type { ChangeEvent, KeyboardEvent } from "react";
import type { Variants } from "@root/questions";
import { ReactNode } from "react";
type AnswerItemProps = {
index: number;
totalIndex: number;
variants: Variants[];
variant: Variants;
icon?: ReactNode;
emoji: boolean;
};
export const AnswerItem = ({
@ -37,12 +38,14 @@ export const AnswerItem = ({
totalIndex,
variants,
variant,
icon,
emoji,
}: AnswerItemProps) => {
const [open, setOpen] = useState<boolean>(false);
const quizId = Number(useParams().quizId);
const { listQuestions } = questionStore();
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down(790));
const anchorElement = useRef();
const debounced = useDebouncedCallback((value) => {
const answerNew = variants.slice();
answerNew[index].answer = value;
@ -69,7 +72,7 @@ export const AnswerItem = ({
const addNewAnswer = () => {
const answerNew = variants.slice();
answerNew.push({ answer: "", hints: "" });
answerNew.push({ answer: "", hints: "", emoji: "" });
updateQuestionsList(quizId, totalIndex, {
content: {
@ -137,19 +140,64 @@ export const AnswerItem = ({
>
<PointsIcon />
</InputAdornment>
{icon && icon}
{emoji && (
<Box sx={{ cursor: "pointer", margin: "0 15px 0 5px" }}>
<Box ref={anchorElement} onClick={() => setOpen(true)}>
<Box
sx={{
display: "flex",
justifyContent: "center",
alignItems: "center",
gap: "5px",
}}
>
<Box sx={{ width: "30px" }}>{variant.emoji}</Box>
<AddEmoji />
</Box>
</Box>
<Popover
open={open}
anchorEl={anchorElement.current}
onClose={() => setOpen(false)}
anchorOrigin={{
vertical: "bottom",
horizontal: "right",
}}
sx={{
".MuiPaper-root.MuiPaper-rounded": {
background: "transparent",
},
}}
>
<EmojiPicker
onEmojiSelect={({ native }) => {
setOpen(false);
const cloneVariants = [...variants];
cloneVariants[index] = {
...cloneVariants[index],
emoji: native,
};
updateQuestionsList(quizId, totalIndex, {
content: {
...listQuestions[quizId][totalIndex].content,
variants: cloneVariants,
},
});
}}
/>
</Popover>
</Box>
)}
</>
),
endAdornment: (
<InputAdornment position="end">
<IconButton
aria-describedby="my-popover-id"
onClick={handleClick}
>
<IconButton onClick={handleClick}>
<MessageIcon />
</IconButton>
<Popover
id="my-popover-id"
open={isOpen}
anchorEl={anchorEl}
onClose={handleClose}
@ -173,7 +221,7 @@ export const AnswerItem = ({
}}
sx={{
"& .MuiInputBase-root": {
padding: icon ? "5px 13.5px" : "13.5px",
padding: emoji ? "5px 13.5px" : "13.5px",
borderRadius: "10px",
background: "#ffffff",
},

@ -8,20 +8,19 @@ import { updateVariants } from "@root/questions";
import { reorder } from "./helper";
import { ReactNode } from "react";
import type { DropResult } from "react-beautiful-dnd";
import type { Variants } from "@root/questions";
type AnswerDraggableListProps = {
variants: Variants[];
totalIndex: number;
icon?: ReactNode;
emoji?: boolean;
};
export const AnswerDraggableList = ({
variants,
totalIndex,
icon,
emoji = false,
}: AnswerDraggableListProps) => {
const quizId = Number(useParams().quizId);
@ -45,7 +44,7 @@ export const AnswerDraggableList = ({
totalIndex={totalIndex}
variants={variants}
variant={variant}
icon={icon}
emoji={emoji}
/>
))}
{provided.placeholder}

@ -68,7 +68,7 @@ export default function ButtonsOptions({ SSHC, switchState, totalIndex }: Props)
}}
>
{buttonSetting.map(({ icon, title, value, myFunc }) => (
<>
<Box key={value}>
{value === "branching" ? (
<Tooltip
arrow
@ -135,7 +135,7 @@ export default function ButtonsOptions({ SSHC, switchState, totalIndex }: Props)
{isMobile ? null : title}
</MiniButtonSetting>
)}
</>
</Box>
))}
</Box>
<Box

@ -27,7 +27,7 @@ export default function DropDown({ totalIndex }: Props) {
const addNewAnswer = () => {
const answerNew = variants.slice();
answerNew.push({ answer: "", hints: "" });
answerNew.push({ answer: "", hints: "", emoji: "" });
updateQuestionsList(quizId, totalIndex, {
content: {
@ -39,7 +39,11 @@ export default function DropDown({ totalIndex }: Props) {
return (
<>
<Box sx={{ padding: isMobile ? "15px 20px 20px 20px" : "20px 20px 20px 20px " }}>
<Box
sx={{
padding: isMobile ? "15px 20px 20px 20px" : "20px 20px 20px 20px ",
}}
>
{variants.length === 0 ? (
<Typography
sx={{
@ -81,7 +85,11 @@ export default function DropDown({ totalIndex }: Props) {
)}
</Box>
</Box>
<ButtonsOptions switchState={switchState} SSHC={SSHC} totalIndex={totalIndex} />
<ButtonsOptions
switchState={switchState}
SSHC={SSHC}
totalIndex={totalIndex}
/>
<SwitchDropDown switchState={switchState} totalIndex={totalIndex} />
</>
);

@ -1,10 +1,9 @@
import { useState } from "react";
import { useParams } from "react-router-dom";
import { Box, Link, Typography, useMediaQuery, useTheme } from "@mui/material";
import EnterIcon from "../../../assets/icons/questionsPage/enterIcon";
import ButtonsOptions from "../ButtonsOptions";
import SwitchEmoji from "./switchEmoji";
import React from "react";
import AddEmoji from "../../../assets/icons/questionsPage/addEmoji";
import { AnswerDraggableList } from "../AnswerDraggableList";
import { questionStore, updateQuestionsList } from "@root/questions";
@ -12,7 +11,7 @@ interface Props {
totalIndex: number;
}
export default function Emoji({ totalIndex }: Props) {
const [switchState, setSwitchState] = React.useState("setting");
const [switchState, setSwitchState] = useState<string>("setting");
const { listQuestions } = questionStore();
const quizId = Number(useParams().quizId);
const theme = useTheme();
@ -28,11 +27,7 @@ export default function Emoji({ totalIndex }: Props) {
<AnswerDraggableList
variants={listQuestions[quizId][totalIndex].content.variants}
totalIndex={totalIndex}
icon={
<Box sx={{ margin: "0 15px 0 5px" }}>
<AddEmoji />
</Box>
}
emoji
/>
<Box sx={{ display: "flex", alignItems: "center", gap: "10px" }}>
<Link
@ -40,8 +35,9 @@ export default function Emoji({ totalIndex }: Props) {
variant="body2"
sx={{ color: theme.palette.brightPurple.main }}
onClick={() => {
const answerNew = listQuestions[quizId][totalIndex].content.variants.slice();
answerNew.push({ answer: "", hints: "" });
const answerNew =
listQuestions[quizId][totalIndex].content.variants.slice();
answerNew.push({ answer: "", hints: "", emoji: "" });
updateQuestionsList(quizId, totalIndex, {
content: {
@ -70,7 +66,11 @@ export default function Emoji({ totalIndex }: Props) {
)}
</Box>
</Box>
<ButtonsOptions switchState={switchState} SSHC={SSHC} totalIndex={totalIndex} />
<ButtonsOptions
switchState={switchState}
SSHC={SSHC}
totalIndex={totalIndex}
/>
<SwitchEmoji switchState={switchState} totalIndex={totalIndex} />
</>
);

@ -28,6 +28,7 @@ export default function OptionsAndPicture({ totalIndex }: Props) {
<Box sx={{ paddingBottom: "25px" }}>
{listQuestions[quizId][totalIndex].content.variants.map((_, index) => (
<ButtonBase
key={index}
component="label"
sx={{
cursor: "pointer",
@ -76,7 +77,7 @@ export default function OptionsAndPicture({ totalIndex }: Props) {
sx={{ color: theme.palette.brightPurple.main }}
onClick={() => {
const clonContent = listQuestions[quizId][totalIndex].content;
clonContent.variants.push({ answer: "", hints: "" });
clonContent.variants.push({ answer: "", hints: "", emoji: "" });
updateQuestionsList(quizId, totalIndex, { content: clonContent });
}}

@ -25,7 +25,7 @@ export default function AnswerOptions({ totalIndex }: Props) {
const addNewAnswer = () => {
const answerNew = variants.slice();
answerNew.push({ answer: "", hints: "" });
answerNew.push({ answer: "", hints: "", emoji: "" });
updateQuestionsList(quizId, totalIndex, {
content: {
@ -87,7 +87,11 @@ export default function AnswerOptions({ totalIndex }: Props) {
)}
</Box>
</Box>
<ButtonsOptionsAndPict switchState={switchState} SSHC={SSHC} totalIndex={totalIndex} />
<ButtonsOptionsAndPict
switchState={switchState}
SSHC={SSHC}
totalIndex={totalIndex}
/>
<SwitchAnswerOptions switchState={switchState} totalIndex={totalIndex} />
</>
);

@ -4,6 +4,7 @@ import { persist } from "zustand/middleware";
export type Variants = {
answer: string;
hints: string;
emoji: string;
};
type Hint = {
@ -121,6 +122,7 @@ export const DEFAULT_QUESTION: Omit<Question, "id"> = {
{
answer: "",
hints: "",
emoji: "",
},
],
hint: {

@ -0,0 +1,19 @@
import EmojiPickerOriginal from "@emoji-mart/react";
type Emoji = {
emoticons: string[];
id: string;
keywords: string[];
name: string;
native: string;
shortcodes: string;
unified: string;
};
type EmojiPickerProps = {
onEmojiSelect: (emoji: Emoji) => void;
};
export const EmojiPicker = ({ onEmojiSelect }: EmojiPickerProps) => (
<EmojiPickerOriginal onEmojiSelect={onEmojiSelect} />
);

@ -1218,6 +1218,16 @@
resolved "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.0.2.tgz"
integrity sha512-IkpVW/ehM1hWKln4fCA3NzJU8KwD+kIOvPZA4cqxoJHtE21CCzjyp+Kxbu0i5I4tBNOlXPL9mjwnWlL0VEG4Fg==
"@emoji-mart/data@^1.1.2":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@emoji-mart/data/-/data-1.1.2.tgz#777c976f8f143df47cbb23a7077c9ca9fe5fc513"
integrity sha512-1HP8BxD2azjqWJvxIaWAMyTySeZY0Osr83ukYjltPVkNXeJvTz7yDrPLBtnrD5uqJ3tg4CcLuuBW09wahqL/fg==
"@emoji-mart/react@^1.1.1":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@emoji-mart/react/-/react-1.1.1.tgz#ddad52f93a25baf31c5383c3e7e4c6e05554312a"
integrity sha512-NMlFNeWgv1//uPsvLxvGQoIerPuVdXwK/EUek8OOkJ6wVOWPUizRBJU0hDqWZCOROVpfBgCemaC3m6jDOXi03g==
"@emotion/babel-plugin@^11.10.5":
version "11.10.5"
resolved "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.10.5.tgz"
@ -4163,6 +4173,11 @@ emittery@^0.8.1:
resolved "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz"
integrity sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==
emoji-mart@^5.5.2:
version "5.5.2"
resolved "https://registry.yarnpkg.com/emoji-mart/-/emoji-mart-5.5.2.tgz#3ddbaf053139cf4aa217650078bc1c50ca8381af"
integrity sha512-Sqc/nso4cjxhOwWJsp9xkVm8OF5c+mJLZJFoFfzRuKO+yWiN7K8c96xmtughYb0d/fZ8UC6cLIQ/p4BR6Pv3/A==
emoji-regex@^8.0.0:
version "8.0.0"
resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz"