This repository has been archived by the owner on Oct 27, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 36
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
35 changed files
with
1,495 additions
and
180 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,180 @@ | ||
import { useEffect, useState } from "react"; | ||
|
||
import { useTranslation } from "next-i18next"; | ||
|
||
import Button from "components/button"; | ||
import CustomContainer from "components/custom-container"; | ||
import { IFilesProps } from "components/drag-and-drop"; | ||
import IssueDescription from "components/issue-description"; | ||
import IssueProposalProgressBar from "components/issue-proposal-progress-bar"; | ||
|
||
import { useAppState } from "contexts/app-state"; | ||
import { addToast } from "contexts/reducers/change-toaster"; | ||
|
||
import { BODY_CHARACTERES_LIMIT } from "helpers/contants"; | ||
|
||
import useApi from "x-hooks/use-api"; | ||
import { useBounty } from "x-hooks/use-bounty"; | ||
|
||
import IssueEditTag from "./issue-edit-tag"; | ||
|
||
interface issueBodyProps { | ||
isEditIssue: boolean; | ||
cancelEditIssue: () => void; | ||
} | ||
|
||
export default function IssueBody({ | ||
isEditIssue, | ||
cancelEditIssue, | ||
}: issueBodyProps) { | ||
const { t } = useTranslation(["common", "bounty"]); | ||
const [body, setBody] = useState<string>(); | ||
const [files, setFiles] = useState<IFilesProps[]>([]); | ||
const [isPreview, setIsPreview] = useState<boolean>(false); | ||
const [selectedTags, setSelectedTags] = useState<string[]>(); | ||
const [isUploading, setIsUploading] = useState<boolean>(false); | ||
const { getDatabaseBounty } = useBounty(); | ||
const { state, dispatch } = useAppState(); | ||
|
||
const { updateIssue } = useApi(); | ||
|
||
useEffect(() => { | ||
if(!state.currentBounty?.data?.body) return; | ||
|
||
setBody(state.currentBounty?.data?.body); | ||
}, [state.currentBounty?.data]); | ||
|
||
function onUpdateFiles(files: IFilesProps[]) { | ||
return setFiles(files); | ||
} | ||
|
||
function addFilesInDescription(str) { | ||
const strFiles = files?.map((file) => | ||
file.uploaded && | ||
`${file?.type?.split("/")[0] === "image" ? "!" : ""}[${file.name}](${ | ||
state.Settings?.urls?.ipfs | ||
}/${file.hash}) \n\n`); | ||
return `${str}\n\n${strFiles | ||
.toString() | ||
.replace(",![", "![") | ||
.replace(",[", "[")}`; | ||
} | ||
|
||
function handleUpdateIssue() { | ||
if ( | ||
(addFilesInDescription(body) === state.currentBounty?.data?.body && | ||
selectedTags === state.currentBounty?.data?.tags) || | ||
!state.currentBounty.data | ||
) | ||
return; | ||
setIsUploading(true); | ||
updateIssue({ | ||
repoId: state.currentBounty?.data?.repository_id, | ||
ghId: state.currentBounty?.data?.githubId, | ||
networkName: state.Service?.network?.active?.name, | ||
body: addFilesInDescription(body), | ||
tags: selectedTags, | ||
}) | ||
.then(() => { | ||
dispatch(addToast({ | ||
type: "success", | ||
title: t("actions.success"), | ||
content: t("bounty:actions.edit-bounty") | ||
})); | ||
getDatabaseBounty(true); | ||
cancelEditIssue(); | ||
setIsPreview(false); | ||
}) | ||
.catch((err) => console.log("update issue error", err)) | ||
.finally(() => setIsUploading(false)); | ||
} | ||
|
||
function handleCancelEdit() { | ||
setIsPreview(false); | ||
cancelEditIssue(); | ||
} | ||
|
||
function isDisableUpdateIssue() { | ||
return (isUploading || addFilesInDescription(body)?.length > BODY_CHARACTERES_LIMIT || body?.length === 0) | ||
} | ||
|
||
if (state.currentUser?.walletAddress) | ||
return ( | ||
<div className="container mb-1"> | ||
<div className="d-flex bd-highlight justify-content-center mx-2 px-4"> | ||
<div className="ps-3 pe-0 ms-0 me-2 w-65 bd-highlight"> | ||
<div className="content-wrapper mb-3"> | ||
{isEditIssue && ( | ||
<div className="d-flex justify-content-center"> | ||
<span className="p family-Regular font-weight-medium mt-1 text-info"> | ||
{t("bounty:edit-text")} | ||
</span> | ||
</div> | ||
)} | ||
<IssueEditTag | ||
isEdit={isEditIssue} | ||
selectedTags={selectedTags} | ||
setSelectedTags={setSelectedTags} | ||
preview={isPreview} | ||
/> | ||
<div className="container"> | ||
<IssueDescription | ||
body={isPreview ? addFilesInDescription(body) : body} | ||
setBody={setBody} | ||
isEdit={isEditIssue} | ||
onUpdateFiles={onUpdateFiles} | ||
onUploading={setIsUploading} | ||
files={files} | ||
preview={isPreview} | ||
/> | ||
</div> | ||
{isEditIssue && ( | ||
<> | ||
<div className="d-flex flex-row justify-content-between my-3"> | ||
<Button | ||
color="danger" | ||
onClick={handleCancelEdit} | ||
disabled={false} | ||
> | ||
{t("bounty:cancel-changes")} | ||
</Button> | ||
<div className="d-flex"> | ||
<Button | ||
outline={true} | ||
className="d-flex flex-shrink-0 w-40 btn-block" | ||
onClick={() => setIsPreview(!isPreview)} | ||
disabled={isUploading} | ||
> | ||
{!isPreview ? t("bounty:preview") : t("bounty:edit")} | ||
</Button> | ||
<Button | ||
className="d-flex flex-shrink-0 w-40 btn-block" | ||
onClick={handleUpdateIssue} | ||
disabled={isDisableUpdateIssue()} | ||
isLoading={isUploading} | ||
> | ||
{t("bounty:save-changes")} | ||
</Button> | ||
</div> | ||
</div> | ||
</> | ||
)} | ||
</div> | ||
</div> | ||
<div className="p-0 me-3 flex-shrink-0 w-25 bd-highlight"> | ||
<div className="sticky-bounty"> | ||
<IssueProposalProgressBar /> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
); | ||
else | ||
return ( | ||
<CustomContainer> | ||
<div className="content-wrapper mb-3"> | ||
<IssueDescription body={body || ""} /> | ||
</div> | ||
</CustomContainer> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
import { useEffect } from "react"; | ||
import { Col, Row } from "react-bootstrap"; | ||
import ReactSelect from "react-select"; | ||
|
||
import { useTranslation } from "next-i18next"; | ||
|
||
import { PROGRAMMING_LANGUAGES } from "assets/bounty-labels"; | ||
|
||
import { ContextualSpan } from "components/contextual-span"; | ||
|
||
import { useAppState } from "contexts/app-state"; | ||
|
||
import { MAX_TAGS } from "helpers/contants"; | ||
|
||
import BountyTags from "./bounty-tags"; | ||
|
||
interface IssueEditTagProps { | ||
isEdit: boolean; | ||
selectedTags: string[]; | ||
setSelectedTags: (v: string[]) => void; | ||
preview?: boolean; | ||
} | ||
|
||
export default function IssueEditTag({ | ||
selectedTags, | ||
setSelectedTags, | ||
isEdit = false, | ||
preview = false, | ||
}: IssueEditTagProps) { | ||
const { t } = useTranslation(["bounty"]); | ||
const { state } = useAppState(); | ||
|
||
const TAGS_OPTIONS = PROGRAMMING_LANGUAGES.map(({ tag }) => ({ | ||
label: tag, | ||
value: tag, | ||
})); | ||
|
||
function handleChangeTags(newTags) { | ||
setSelectedTags(newTags.map(({ value }) => value)); | ||
} | ||
|
||
useEffect(() => { | ||
setSelectedTags(TAGS_OPTIONS.filter((tag) => | ||
state.currentBounty?.data?.tags?.includes(tag.value)).map((e) => e.value)); | ||
}, [state.currentBounty?.data?.tags]); | ||
|
||
if (isEdit) | ||
return ( | ||
<div className="cointainer mb-4 form-group"> | ||
<h3 className="caption-large ms-2 mb-2">{t("tags")}</h3> | ||
<Row className="justify-content-center p-0 m-0 form-group"> | ||
{preview ? ( | ||
<Col className="col-12"> | ||
<BountyTags tags={selectedTags} /> | ||
</Col> | ||
): ( | ||
<> | ||
<Col className="col-12 text-black"> | ||
<ReactSelect | ||
value={selectedTags?.map((tag) => ({ label: tag, value: tag }))} | ||
options={TAGS_OPTIONS} | ||
onChange={handleChangeTags} | ||
isOptionDisabled={() => selectedTags.length >= MAX_TAGS} | ||
isMulti | ||
/> | ||
</Col> | ||
<Col> | ||
<ContextualSpan context="info" className="mt-2"> | ||
{t("fields.tags-info")} | ||
</ContextualSpan> | ||
</Col> | ||
</> | ||
)} | ||
</Row> | ||
</div> | ||
); | ||
|
||
return null; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.