diff --git a/src/Components/Inputs/FilesInputs/ScreenshotsInput/ImagePreviews.tsx b/src/Components/Inputs/FilesInputs/ScreenshotsInput/ImagePreviews.tsx index 74d4d64..2917436 100644 --- a/src/Components/Inputs/FilesInputs/ScreenshotsInput/ImagePreviews.tsx +++ b/src/Components/Inputs/FilesInputs/ScreenshotsInput/ImagePreviews.tsx @@ -1,5 +1,5 @@ import UploadPreview, { PreviewComponentProps, PreviewMethods } from '@rpldy/upload-preview' -import { useAbortItem, useItemAbortListener, useItemCancelListener, useItemErrorListener, useItemProgressListener } from '@rpldy/uploady'; +import { useAbortItem, useItemAbortListener, useItemCancelListener, useItemErrorListener, useItemFinishListener, useItemProgressListener } from '@rpldy/uploady'; import { useState } from 'react' import ScreenShotsThumbnail from './ScreenshotThumbnail' @@ -20,15 +20,11 @@ function CustomImagePreview({ id, url }: PreviewComponentProps) { useItemProgressListener(item => { if (item.completed > progress) { setProgress(() => item.completed); - - if (item.completed === 100) { - setItemState(STATES.DONE) - } else { - setItemState(STATES.PROGRESS) - } } }, id); + useItemFinishListener(() => setItemState(STATES.DONE), id) + useItemAbortListener(item => { @@ -41,7 +37,10 @@ function CustomImagePreview({ id, url }: PreviewComponentProps) { }, id); useItemErrorListener(item => { + console.log(item); + setItemState(STATES.ERROR); + setTimeout(() => setItemState(STATES.CANCELLED), 2000) }, id); if (itemState === STATES.DONE || itemState === STATES.CANCELLED) diff --git a/src/Components/Inputs/FilesInputs/ScreenshotsInput/ScreenshotThumbnail.tsx b/src/Components/Inputs/FilesInputs/ScreenshotsInput/ScreenshotThumbnail.tsx index a7d3199..5f64ac6 100644 --- a/src/Components/Inputs/FilesInputs/ScreenshotsInput/ScreenshotThumbnail.tsx +++ b/src/Components/Inputs/FilesInputs/ScreenshotsInput/ScreenshotThumbnail.tsx @@ -45,7 +45,7 @@ export default function ScreenshotThumbnail({ url, isLoading, isError, onCancel Failed... } {!isEmpty && - + } ) diff --git a/src/Components/Inputs/FilesInputs/ScreenshotsInput/ScreenshotsInput.tsx b/src/Components/Inputs/FilesInputs/ScreenshotsInput/ScreenshotsInput.tsx index 4893118..d4481e7 100644 --- a/src/Components/Inputs/FilesInputs/ScreenshotsInput/ScreenshotsInput.tsx +++ b/src/Components/Inputs/FilesInputs/ScreenshotsInput/ScreenshotsInput.tsx @@ -13,6 +13,7 @@ import { FiCamera } from "react-icons/fi"; import { Control, Path, useController } from "react-hook-form"; import { ImageInput } from "src/graphql"; import { fetchUploadImageUrl } from "src/api/uploading"; +import { removeArrayItemAtIndex } from "src/utils/helperFunctions"; @@ -43,6 +44,7 @@ export default function ScreenshotsInput(props: Props) { return ( setUploadingCount(v => v - 1), [UPLOADER_EVENTS.ITEM_FINISH]: (item) => { - // Just for mocking purposes - const dataUrl = URL.createObjectURL(item.file); + const { id, filename, variants } = item?.uploadResponse?.data?.result; - const { id, filename, variants } = item?.uploadResponse?.data?.result ?? { - id: Math.random().toString(), - filename: item.file.name, - variants: [ - "", - dataUrl - ] - } - if (id) { - onChange([...uploadedFiles, { id, name: filename, url: variants[1] }].slice(-MAX_UPLOAD_COUNT)) + const url = (variants as string[]).find(v => v.includes('public')); + + if (id && url) { + onChange([...uploadedFiles, { id, name: filename, url: url }].slice(-MAX_UPLOAD_COUNT)) } } }} >
- {canUploadMore && } - {uploadedFiles.map(f => + {uploadedFiles.map((f, idx) => { - onChange(uploadedFiles.filter(file => file.id !== f.id)) + onChange(removeArrayItemAtIndex(uploadedFiles, idx)) }} />)} {(placeholdersCount > 0) && @@ -88,7 +83,7 @@ export default function ScreenshotsInput(props: Props) { } const DropZone = forwardRef((props, ref) => { - const { onClick, ...buttonProps } = props; + const { canUploadMore, onClick, ...buttonProps } = props; useRequestPreSend(async (data) => { @@ -115,6 +110,8 @@ const DropZone = forwardRef((props, ref) => { [onClick] ); + if (!canUploadMore) return null + return = yup.object({ description: yup.string().trim().required().min(50, 'Write at least 10 words descriping your project'), thumbnail_image: imageSchema.required("Please pick a thumbnail image").default(undefined), cover_image: imageSchema.required("Please pick a cover image").default(undefined), - twitter: yup.string().url(), - discord: yup.string().url(), - github: yup.string().url(), - slack: yup.string().url(), - telegram: yup.string().url(), + twitter: yup.string().url().nullable(), + discord: yup.string().url().nullable(), + github: yup.string().url().nullable(), + slack: yup.string().url().nullable(), + telegram: yup.string().url().nullable(), category_id: yup.number().required("Please choose a category"), capabilities: yup.array().of(yup.number().required()).default([]), screenshots: yup.array().of(imageSchema.required()).default([]), diff --git a/src/features/Projects/pages/ListProjectPage/Components/FormContainer/listProject.graphql b/src/features/Projects/pages/ListProjectPage/Components/FormContainer/listProject.graphql index a3f58c6..6eb9015 100644 --- a/src/features/Projects/pages/ListProjectPage/Components/FormContainer/listProject.graphql +++ b/src/features/Projects/pages/ListProjectPage/Components/FormContainer/listProject.graphql @@ -1,51 +1,64 @@ +fragment ProjectDetails on Project { + id + title + tagline + description + hashtag + cover_image + thumbnail_image + launch_status + twitter + discord + github + slack + telegram + screenshots + website + lightning_address + votes_count + category { + id + icon + title + } + permissions + members { + role + user { + id + name + jobTitle + avatar + } + } + awards { + title + image + url + id + } + tags { + id + title + } + recruit_roles { + id + title + icon + level + } + + capabilities { + id + title + icon + } +} + mutation CreateProject($input: CreateProjectInput) { createProject(input: $input) { project { - id - title - description - cover_image - thumbnail_image - screenshots - website - lightning_address - lnurl_callback_url - votes_count - category { - id - icon - title - } - members { - role - user { - id - name - avatar - } - } - awards { - title - image - url - id - } - tags { - id - title - } - recruit_roles { - id - title - icon - level - } - - capabilities { - id - title - icon - } + ...ProjectDetails } } } @@ -53,52 +66,7 @@ mutation CreateProject($input: CreateProjectInput) { mutation UpdateProject($input: UpdateProjectInput) { updateProject(input: $input) { project { - id - title - description - cover_image - thumbnail_image - screenshots - website - lightning_address - lnurl_callback_url - votes_count - - category { - id - icon - title - } - members { - role - user { - id - name - avatar - } - } - awards { - title - image - url - id - } - tags { - id - title - } - recruit_roles { - id - title - icon - level - } - - capabilities { - id - title - icon - } + ...ProjectDetails } } } diff --git a/src/features/Projects/pages/ProjectPage/ProjectDetailsCard/ProjectDetailsCard.Skeleton.tsx b/src/features/Projects/pages/ProjectPage/ProjectDetailsCard/ProjectDetailsCard.Skeleton.tsx index 619ae57..2501813 100644 --- a/src/features/Projects/pages/ProjectPage/ProjectDetailsCard/ProjectDetailsCard.Skeleton.tsx +++ b/src/features/Projects/pages/ProjectPage/ProjectDetailsCard/ProjectDetailsCard.Skeleton.tsx @@ -18,8 +18,6 @@ export default function ProjectDetailsCardSkeleton({ onClose, direction, ...prop const isMdScreen = useMediaQuery(MEDIA_QUERIES.isMedium) - - return (
diff --git a/src/features/Projects/pages/ProjectPage/ProjectDetailsCard/ProjectDetailsCard.tsx b/src/features/Projects/pages/ProjectPage/ProjectDetailsCard/ProjectDetailsCard.tsx index cc5e5a0..5e14a66 100644 --- a/src/features/Projects/pages/ProjectPage/ProjectDetailsCard/ProjectDetailsCard.tsx +++ b/src/features/Projects/pages/ProjectPage/ProjectDetailsCard/ProjectDetailsCard.tsx @@ -1,5 +1,5 @@ import { useEffect, useState } from 'react' -import { MdClose, MdLocalFireDepartment } from 'react-icons/md'; +import { MdClose, MdEdit, MdLocalFireDepartment } from 'react-icons/md'; import { ModalCard } from 'src/Components/Modals/ModalsContainer/ModalsContainer'; import { useAppDispatch, useAppSelector, useMediaQuery } from 'src/utils/hooks'; import { openModal, scheduleModal } from 'src/redux/features/modals.slice'; @@ -8,7 +8,7 @@ import Button from 'src/Components/Button/Button'; import ProjectCardSkeleton from './ProjectDetailsCard.Skeleton' // import VoteButton from 'src/features/Projects/pages/ProjectPage/VoteButton/VoteButton'; import { NotificationsService, Wallet_Service } from 'src/services' -import { useProjectDetailsQuery } from 'src/graphql'; +import { ProjectPermissionEnum, useProjectDetailsQuery } from 'src/graphql'; import Lightbox from 'src/Components/Lightbox/Lightbox' import linkifyHtml from 'linkify-html'; import ErrorMessage from 'src/Components/Errors/ErrorMessage/ErrorMessage'; @@ -108,6 +108,8 @@ export default function ProjectDetailsCard({ direction, projectId, ...props }: P }, ]; + const canEdit = project.permissions.includes(ProjectPermissionEnum.UpdateInfo); + const onVote = (votes?: number) => { dispatch(setVoteAmount(votes ?? 10)); dispatch(openModal({ @@ -140,9 +142,14 @@ export default function ProjectDetailsCard({ direction, projectId, ...props }: P {/* Cover Image */}
- +
+ +
+ +
+ {/* Title & Basic Info */}
@@ -171,6 +178,7 @@ export default function ProjectDetailsCard({ direction, projectId, ...props }: P
+ {/* About */}

About

diff --git a/src/graphql/index.tsx b/src/graphql/index.tsx index b6756d2..370c99a 100644 --- a/src/graphql/index.tsx +++ b/src/graphql/index.tsx @@ -1040,19 +1040,21 @@ export type GetAllCapabilitiesQueryVariables = Exact<{ [key: string]: never; }>; export type GetAllCapabilitiesQuery = { __typename?: 'Query', getAllCapabilities: Array<{ __typename?: 'Capability', id: number, title: string, icon: string }> }; +export type ProjectDetailsFragment = { __typename?: 'Project', id: number, title: string, tagline: string, description: string, hashtag: string, cover_image: string, thumbnail_image: string, launch_status: ProjectLaunchStatusEnum, twitter: string | null, discord: string | null, github: string | null, slack: string | null, telegram: string | null, screenshots: Array, website: string, lightning_address: string | null, votes_count: number, permissions: Array, category: { __typename?: 'Category', id: number, icon: string | null, title: string }, members: Array<{ __typename?: 'ProjectMember', role: Team_Member_Role, user: { __typename?: 'User', id: number, name: string, jobTitle: string | null, avatar: string } }>, awards: Array<{ __typename?: 'Award', title: string, image: string, url: string, id: number }>, tags: Array<{ __typename?: 'Tag', id: number, title: string }>, recruit_roles: Array<{ __typename?: 'MakerRole', id: number, title: string, icon: string, level: RoleLevelEnum }>, capabilities: Array<{ __typename?: 'Capability', id: number, title: string, icon: string }> }; + export type CreateProjectMutationVariables = Exact<{ input: InputMaybe; }>; -export type CreateProjectMutation = { __typename?: 'Mutation', createProject: { __typename?: 'CreateProjectResponse', project: { __typename?: 'Project', id: number, title: string, description: string, cover_image: string, thumbnail_image: string, screenshots: Array, website: string, lightning_address: string | null, lnurl_callback_url: string | null, votes_count: number, category: { __typename?: 'Category', id: number, icon: string | null, title: string }, members: Array<{ __typename?: 'ProjectMember', role: Team_Member_Role, user: { __typename?: 'User', id: number, name: string, avatar: string } }>, awards: Array<{ __typename?: 'Award', title: string, image: string, url: string, id: number }>, tags: Array<{ __typename?: 'Tag', id: number, title: string }>, recruit_roles: Array<{ __typename?: 'MakerRole', id: number, title: string, icon: string, level: RoleLevelEnum }>, capabilities: Array<{ __typename?: 'Capability', id: number, title: string, icon: string }> } } | null }; +export type CreateProjectMutation = { __typename?: 'Mutation', createProject: { __typename?: 'CreateProjectResponse', project: { __typename?: 'Project', id: number, title: string, tagline: string, description: string, hashtag: string, cover_image: string, thumbnail_image: string, launch_status: ProjectLaunchStatusEnum, twitter: string | null, discord: string | null, github: string | null, slack: string | null, telegram: string | null, screenshots: Array, website: string, lightning_address: string | null, votes_count: number, permissions: Array, category: { __typename?: 'Category', id: number, icon: string | null, title: string }, members: Array<{ __typename?: 'ProjectMember', role: Team_Member_Role, user: { __typename?: 'User', id: number, name: string, jobTitle: string | null, avatar: string } }>, awards: Array<{ __typename?: 'Award', title: string, image: string, url: string, id: number }>, tags: Array<{ __typename?: 'Tag', id: number, title: string }>, recruit_roles: Array<{ __typename?: 'MakerRole', id: number, title: string, icon: string, level: RoleLevelEnum }>, capabilities: Array<{ __typename?: 'Capability', id: number, title: string, icon: string }> } } | null }; export type UpdateProjectMutationVariables = Exact<{ input: InputMaybe; }>; -export type UpdateProjectMutation = { __typename?: 'Mutation', updateProject: { __typename?: 'CreateProjectResponse', project: { __typename?: 'Project', id: number, title: string, description: string, cover_image: string, thumbnail_image: string, screenshots: Array, website: string, lightning_address: string | null, lnurl_callback_url: string | null, votes_count: number, category: { __typename?: 'Category', id: number, icon: string | null, title: string }, members: Array<{ __typename?: 'ProjectMember', role: Team_Member_Role, user: { __typename?: 'User', id: number, name: string, avatar: string } }>, awards: Array<{ __typename?: 'Award', title: string, image: string, url: string, id: number }>, tags: Array<{ __typename?: 'Tag', id: number, title: string }>, recruit_roles: Array<{ __typename?: 'MakerRole', id: number, title: string, icon: string, level: RoleLevelEnum }>, capabilities: Array<{ __typename?: 'Capability', id: number, title: string, icon: string }> } } | null }; +export type UpdateProjectMutation = { __typename?: 'Mutation', updateProject: { __typename?: 'CreateProjectResponse', project: { __typename?: 'Project', id: number, title: string, tagline: string, description: string, hashtag: string, cover_image: string, thumbnail_image: string, launch_status: ProjectLaunchStatusEnum, twitter: string | null, discord: string | null, github: string | null, slack: string | null, telegram: string | null, screenshots: Array, website: string, lightning_address: string | null, votes_count: number, permissions: Array, category: { __typename?: 'Category', id: number, icon: string | null, title: string }, members: Array<{ __typename?: 'ProjectMember', role: Team_Member_Role, user: { __typename?: 'User', id: number, name: string, jobTitle: string | null, avatar: string } }>, awards: Array<{ __typename?: 'Award', title: string, image: string, url: string, id: number }>, tags: Array<{ __typename?: 'Tag', id: number, title: string }>, recruit_roles: Array<{ __typename?: 'MakerRole', id: number, title: string, icon: string, level: RoleLevelEnum }>, capabilities: Array<{ __typename?: 'Capability', id: number, title: string, icon: string }> } } | null }; export type IsValidProjectHashtagQueryVariables = Exact<{ hashtag: Scalars['String']; @@ -1181,6 +1183,63 @@ export const UserRolesSkillsFragmentDoc = gql` } } `; +export const ProjectDetailsFragmentDoc = gql` + fragment ProjectDetails on Project { + id + title + tagline + description + hashtag + cover_image + thumbnail_image + launch_status + twitter + discord + github + slack + telegram + screenshots + website + lightning_address + votes_count + category { + id + icon + title + } + permissions + members { + role + user { + id + name + jobTitle + avatar + } + } + awards { + title + image + url + id + } + tags { + id + title + } + recruit_roles { + id + title + icon + level + } + capabilities { + id + title + icon + } +} + `; export const OfficialTagsDocument = gql` query OfficialTags { officialTags { @@ -2477,54 +2536,11 @@ export const CreateProjectDocument = gql` mutation CreateProject($input: CreateProjectInput) { createProject(input: $input) { project { - id - title - description - cover_image - thumbnail_image - screenshots - website - lightning_address - lnurl_callback_url - votes_count - category { - id - icon - title - } - members { - role - user { - id - name - avatar - } - } - awards { - title - image - url - id - } - tags { - id - title - } - recruit_roles { - id - title - icon - level - } - capabilities { - id - title - icon - } + ...ProjectDetails } } } - `; + ${ProjectDetailsFragmentDoc}`; export type CreateProjectMutationFn = Apollo.MutationFunction; /** @@ -2555,54 +2571,11 @@ export const UpdateProjectDocument = gql` mutation UpdateProject($input: UpdateProjectInput) { updateProject(input: $input) { project { - id - title - description - cover_image - thumbnail_image - screenshots - website - lightning_address - lnurl_callback_url - votes_count - category { - id - icon - title - } - members { - role - user { - id - name - avatar - } - } - awards { - title - image - url - id - } - tags { - id - title - } - recruit_roles { - id - title - icon - level - } - capabilities { - id - title - icon - } + ...ProjectDetails } } } - `; + ${ProjectDetailsFragmentDoc}`; export type UpdateProjectMutationFn = Apollo.MutationFunction; /** diff --git a/src/utils/helperFunctions.tsx b/src/utils/helperFunctions.tsx index 69bf086..09cd597 100644 --- a/src/utils/helperFunctions.tsx +++ b/src/utils/helperFunctions.tsx @@ -182,3 +182,8 @@ export const getSpanDate = (_date1: string, _date2: string) => { return `${dayjs(_date1).format('H:mm')} - ${dayjs(_date2).format('H:mm, Do MMM')}` } + + +export function removeArrayItemAtIndex(arr: T[], indexToRemove: number) { + return [...arr.slice(0, indexToRemove), ...arr.slice(indexToRemove + 1)] +} \ No newline at end of file