Skip to content
This repository has been archived by the owner on Oct 27, 2023. It is now read-only.

Commit

Permalink
BEPRO 2.10 (#890)
Browse files Browse the repository at this point in the history
  • Loading branch information
moshmage authored Mar 6, 2023
2 parents e689e3e + e980146 commit 26f957f
Show file tree
Hide file tree
Showing 35 changed files with 1,495 additions and 180 deletions.
2 changes: 2 additions & 0 deletions components/bounties/list-active-networks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { useRouter } from "next/router";

import CardItem from "components/card-item";
import CustomContainer from "components/custom-container";
import NothingFound from "components/nothing-found";

import { useAppState } from "contexts/app-state";

Expand Down Expand Up @@ -95,6 +96,7 @@ export default function ListActiveNetworks() {
</CardItem>
</div>
))}
{networks?.length === 0 && <NothingFound description={t("most-active-network-empty")}/>}
</div>
</CustomContainer>
);
Expand Down
180 changes: 180 additions & 0 deletions components/bounty/issue-body.tsx
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>
);
}
79 changes: 79 additions & 0 deletions components/bounty/issue-edit-tag.tsx
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;
}
9 changes: 3 additions & 6 deletions components/create-bounty-details.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import ReactSelect from "components/react-select";

import { useAppState } from "contexts/app-state";

import { BODY_CHARACTERES_LIMIT } from "helpers/contants";
import { BODY_CHARACTERES_LIMIT, BOUNTY_TITLE_LIMIT, MAX_TAGS } from "helpers/contants";

export default function CreateBountyDetails({
bountyTitle,
Expand All @@ -37,9 +37,6 @@ export default function CreateBountyDetails({
state: { Settings },
} = useAppState();


const titleLimit = 131;
const MAX_TAGS = 3;
const TAGS_OPTIONS = PROGRAMMING_LANGUAGES.map(({ tag }) => ({ label: tag, value: tag }));

function handleShowModal() {
Expand Down Expand Up @@ -96,14 +93,14 @@ export default function CreateBountyDetails({
<input
type="text"
className={clsx("form-control rounded-lg", {
"border border-1 border-danger border-radius-8": bountyTitle.length >= titleLimit
"border border-1 border-danger border-radius-8": bountyTitle.length >= BOUNTY_TITLE_LIMIT
})}
placeholder={t("fields.title.placeholder")}
value={bountyTitle}
onChange={handleChangeTitle}
disabled={review}
/>
{bountyTitle.length >= titleLimit && (
{bountyTitle.length >= BOUNTY_TITLE_LIMIT && (
<span className="caption-small mt-3 text-danger bg-opacity-100">
{t("errors.title-character-limit", {value: bountyTitle?.length})}
</span>
Expand Down
7 changes: 5 additions & 2 deletions components/image-uploader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ export default function ImageUploader({
onChange,
lg = false,
error = false,
className = ""
className = "",
isLoading = false,
}) {
const { t } = useTranslation("custom-network");

Expand Down Expand Up @@ -45,7 +46,9 @@ export default function ImageUploader({
} ${className}`}
htmlFor={name}
>
{image.preview || typeof image === "string" ? (
{isLoading ? (
<span className="spinner-border spinner-border-xs ml-1" />
) : image.preview || typeof image === "string" ? (
<img
src={image.preview || image}
alt="dummy"
Expand Down
Loading

0 comments on commit 26f957f

Please sign in to comment.