mirror of
https://github.com/aljazceru/landscape-template.git
synced 2026-01-29 19:24:27 +01:00
Merge branch 'dev' into feature/list-your-product-ui
This commit is contained in:
@@ -10,17 +10,12 @@ import Button from "src/Components/Button/Button";
|
||||
import { FiCopy } from "react-icons/fi";
|
||||
import useCopyToClipboard from "src/utils/hooks/useCopyToClipboard";
|
||||
import { getPropertyFromUnknown, trimText, } from "src/utils/helperFunctions";
|
||||
import { fetchIsLoggedIn, fetchLnurlAuth } from "src/api/auth";
|
||||
import { useErrorHandler } from 'react-error-boundary';
|
||||
|
||||
|
||||
|
||||
const fetchLnurlAuth = async () => {
|
||||
const res = await fetch(CONSTS.apiEndpoint + '/get-login-url', {
|
||||
credentials: 'include'
|
||||
})
|
||||
const data = await res.json()
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
export const useLnurlQuery = () => {
|
||||
const [loading, setLoading] = useState(true)
|
||||
@@ -102,15 +97,9 @@ export default function LoginPage() {
|
||||
if (canFetchIsLogged.current === false) return;
|
||||
|
||||
canFetchIsLogged.current = false;
|
||||
fetch(CONSTS.apiEndpoint + '/is-logged-in', {
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
session_token
|
||||
}
|
||||
})
|
||||
.then(data => data.json())
|
||||
.then(data => {
|
||||
if (data.logged_in) {
|
||||
fetchIsLoggedIn(session_token)
|
||||
.then(is_logged_in => {
|
||||
if (is_logged_in) {
|
||||
clearInterval(interval)
|
||||
refetch();
|
||||
}
|
||||
|
||||
@@ -2,8 +2,9 @@ import { yupResolver } from "@hookform/resolvers/yup";
|
||||
import { Controller, FormProvider, NestedValue, Resolver, SubmitHandler, useForm } from "react-hook-form";
|
||||
import Button from "src/Components/Button/Button";
|
||||
import DatePicker from "src/Components/Inputs/DatePicker/DatePicker";
|
||||
import FilesInput from "src/Components/Inputs/FilesInput/FilesInput";
|
||||
import TagsInput from "src/Components/Inputs/TagsInput/TagsInput";
|
||||
import { Tag } from "src/graphql";
|
||||
import { imageSchema } from "src/utils/validation";
|
||||
import * as yup from "yup";
|
||||
import ContentEditor from "../ContentEditor/ContentEditor";
|
||||
|
||||
@@ -31,29 +32,14 @@ const schema = yup.object({
|
||||
.string()
|
||||
.required()
|
||||
.min(50, 'you have to write at least 10 words'),
|
||||
cover_image: yup
|
||||
.lazy((value: string | File[]) => {
|
||||
switch (typeof value) {
|
||||
case 'object':
|
||||
return yup
|
||||
.array()
|
||||
.test("fileSize", "File Size is too large", (files) => (files as File[]).every(file => file.size <= 5242880))
|
||||
.test("fileType", "Unsupported File Format, only png/jpg/jpeg images are allowed",
|
||||
(files) => (files as File[]).every((file: File) =>
|
||||
["image/jpeg", "image/png", "image/jpg"].includes(file.type)))
|
||||
case 'string':
|
||||
return yup.string().url();
|
||||
default:
|
||||
return yup.mixed()
|
||||
}
|
||||
})
|
||||
cover_image: imageSchema,
|
||||
}).required();
|
||||
|
||||
interface IFormInputs {
|
||||
title: string
|
||||
deadline: Date
|
||||
bounty_amount: number
|
||||
tags: NestedValue<object[]>
|
||||
tags: NestedValue<Tag[]>
|
||||
cover_image: NestedValue<File[]> | string
|
||||
body: string
|
||||
}
|
||||
@@ -86,7 +72,7 @@ export default function BountyForm() {
|
||||
<div
|
||||
className='bg-white shadow-lg rounded-8 overflow-hidden'>
|
||||
<div className="p-32">
|
||||
<Controller
|
||||
{/* <Controller
|
||||
control={control}
|
||||
name="cover_image"
|
||||
render={({ field: { onChange, value, onBlur } }) => (
|
||||
@@ -97,7 +83,7 @@ export default function BountyForm() {
|
||||
uploadText='Add a cover image'
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
/> */}
|
||||
<p className='input-error'>{errors.cover_image?.message}</p>
|
||||
|
||||
|
||||
@@ -155,10 +141,20 @@ export default function BountyForm() {
|
||||
<p className="text-body5 mt-16">
|
||||
Tags
|
||||
</p>
|
||||
<TagsInput
|
||||
placeholder="Enter your tag and click enter. You can add multiple tags to your post"
|
||||
classes={{ container: 'mt-8' }}
|
||||
<Controller
|
||||
control={control}
|
||||
name="tags"
|
||||
render={({ field: { onChange, value, onBlur } }) => (
|
||||
<TagsInput
|
||||
placeholder="Add up to 5 popular tags..."
|
||||
classes={{ container: 'mt-16' }}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
onBlur={onBlur}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
||||
{errors.tags && <p className="input-error">
|
||||
{errors.tags.message}
|
||||
</p>}
|
||||
|
||||
@@ -14,7 +14,6 @@ export default {
|
||||
decorators: [WithModals, WrapForm<IStoryFormInputs>({
|
||||
defaultValues: {
|
||||
tags: [],
|
||||
cover_image: [],
|
||||
}
|
||||
})]
|
||||
} as ComponentMeta<typeof DraftsContainer>;
|
||||
|
||||
@@ -10,7 +10,7 @@ import { NotificationsService } from 'src/services';
|
||||
import { getDateDifference } from 'src/utils/helperFunctions';
|
||||
import { useAppDispatch } from 'src/utils/hooks';
|
||||
import { useReduxEffect } from 'src/utils/hooks/useReduxEffect';
|
||||
import { IStoryFormInputs } from '../../CreateStoryPage/CreateStoryPage';
|
||||
import { CreateStoryType, IStoryFormInputs } from '../../CreateStoryPage/CreateStoryPage';
|
||||
|
||||
interface Props {
|
||||
id?: string;
|
||||
@@ -28,7 +28,7 @@ export default function DraftsContainer({ id, type, onDraftLoad }: Props) {
|
||||
const [deleteStory] = useDeleteStoryMutation({
|
||||
refetchQueries: ['GetMyDrafts']
|
||||
})
|
||||
const { setValue } = useFormContext<IStoryFormInputs>()
|
||||
const { setValue } = useFormContext<CreateStoryType>()
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const [loading, setLoading] = useState(false)
|
||||
@@ -45,7 +45,7 @@ export default function DraftsContainer({ id, type, onDraftLoad }: Props) {
|
||||
setValue('title', data.getPostById.title);
|
||||
setValue('tags', data.getPostById.tags);
|
||||
setValue('body', data.getPostById.body);
|
||||
setValue('cover_image', data.getPostById.cover_image ? [data.getPostById.cover_image] : []);
|
||||
setValue('cover_image', data.getPostById.cover_image ? { url: data.getPostById.cover_image, id: null, name: null } : null);
|
||||
setValue('is_published', data.getPostById.is_published);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { yupResolver } from "@hookform/resolvers/yup";
|
||||
import { Controller, FormProvider, NestedValue, Resolver, SubmitHandler, useForm } from "react-hook-form";
|
||||
import Button from "src/Components/Button/Button";
|
||||
import FilesInput from "src/Components/Inputs/FilesInput/FilesInput";
|
||||
import TagsInput from "src/Components/Inputs/TagsInput/TagsInput";
|
||||
import { Tag } from "src/graphql";
|
||||
import * as yup from "yup";
|
||||
import ContentEditor from "../ContentEditor/ContentEditor";
|
||||
|
||||
@@ -29,7 +29,7 @@ const schema = yup.object({
|
||||
|
||||
interface IFormInputs {
|
||||
title: string
|
||||
tags: NestedValue<object[]>
|
||||
tags: NestedValue<Tag[]>
|
||||
cover_image: NestedValue<File[]> | string
|
||||
body: string
|
||||
}
|
||||
@@ -60,7 +60,7 @@ export default function QuestionForm() {
|
||||
<div
|
||||
className='bg-white shadow-lg rounded-8 overflow-hidden'>
|
||||
<div className="p-32">
|
||||
<Controller
|
||||
{/* <Controller
|
||||
control={control}
|
||||
name="cover_image"
|
||||
render={({ field: { onChange, value, onBlur } }) => (
|
||||
@@ -71,7 +71,7 @@ export default function QuestionForm() {
|
||||
uploadText='Add a cover image'
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
/> */}
|
||||
<p className='input-error'>{errors.cover_image?.message}</p>
|
||||
|
||||
|
||||
@@ -95,9 +95,18 @@ export default function QuestionForm() {
|
||||
<p className="text-body5 mt-16">
|
||||
Tags
|
||||
</p>
|
||||
<TagsInput
|
||||
placeholder="Enter your tag and click enter. You can add multiple tags to your post"
|
||||
classes={{ container: 'mt-8' }}
|
||||
<Controller
|
||||
control={control}
|
||||
name="tags"
|
||||
render={({ field: { onChange, value, onBlur } }) => (
|
||||
<TagsInput
|
||||
placeholder="Add up to 5 popular tags..."
|
||||
classes={{ container: 'mt-16' }}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
onBlur={onBlur}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
{errors.tags && <p className="input-error">
|
||||
{errors.tags.message}
|
||||
|
||||
@@ -13,7 +13,6 @@ export default {
|
||||
decorators: [WithModals, WrapForm<IStoryFormInputs>({
|
||||
defaultValues: {
|
||||
tags: [],
|
||||
cover_image: [],
|
||||
}
|
||||
})]
|
||||
} as ComponentMeta<typeof StoryForm>;
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import { Controller, useFormContext } from "react-hook-form";
|
||||
import Button from "src/Components/Button/Button";
|
||||
import FilesInput from "src/Components/Inputs/FilesInput/FilesInput";
|
||||
import TagsInput from "src/Components/Inputs/TagsInput/TagsInput";
|
||||
import ContentEditor from "../ContentEditor/ContentEditor";
|
||||
import { useCreateStoryMutation } from 'src/graphql'
|
||||
@@ -13,7 +12,8 @@ import { createRoute } from 'src/utils/routing';
|
||||
import PreviewPostCard from '../PreviewPostCard/PreviewPostCard'
|
||||
import { StorageService } from 'src/services';
|
||||
import { useThrottledCallback } from '@react-hookz/web';
|
||||
import { CreateStoryType, IStoryFormInputs } from '../../CreateStoryPage/CreateStoryPage';
|
||||
import { CreateStoryType } from '../../CreateStoryPage/CreateStoryPage';
|
||||
import CoverImageInput from 'src/Components/Inputs/FilesInputs/CoverImageInput/CoverImageInput';
|
||||
|
||||
interface Props {
|
||||
isUpdating?: boolean;
|
||||
@@ -29,7 +29,7 @@ export default function StoryForm(props: Props) {
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
const navigate = useNavigate();
|
||||
const { handleSubmit, control, register, trigger, getValues, watch, reset } = useFormContext<IStoryFormInputs>();
|
||||
const { handleSubmit, control, register, trigger, getValues, watch, reset } = useFormContext<CreateStoryType>();
|
||||
|
||||
|
||||
const [editMode, setEditMode] = useState(true)
|
||||
@@ -80,7 +80,7 @@ export default function StoryForm(props: Props) {
|
||||
refetchQueries: ['GetMyDrafts']
|
||||
});
|
||||
|
||||
const clickSubmit = (publish_now: boolean) => handleSubmit<IStoryFormInputs>(data => {
|
||||
const clickSubmit = (publish_now: boolean) => handleSubmit<CreateStoryType>(data => {
|
||||
setLoading(true);
|
||||
createStory({
|
||||
variables: {
|
||||
@@ -90,7 +90,7 @@ export default function StoryForm(props: Props) {
|
||||
body: data.body,
|
||||
tags: data.tags.map(t => t.title),
|
||||
is_published: publish_now,
|
||||
cover_image: (data.cover_image[0] ?? null) as string | null,
|
||||
cover_image: data.cover_image,
|
||||
},
|
||||
}
|
||||
})
|
||||
@@ -103,6 +103,8 @@ export default function StoryForm(props: Props) {
|
||||
const { ref: registerTitleRef, ...titleRegisteration } = register('title');
|
||||
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<div id='preview-switch' className="flex gap-16">
|
||||
@@ -117,19 +119,21 @@ export default function StoryForm(props: Props) {
|
||||
<div
|
||||
className='bg-white border-2 border-gray-200 rounded-16 overflow-hidden'>
|
||||
<div className="p-16 md:p-24 lg:p-32">
|
||||
<Controller
|
||||
control={control}
|
||||
name="cover_image"
|
||||
render={({ field: { onChange, value, onBlur, ref } }) => (
|
||||
<FilesInput
|
||||
ref={ref}
|
||||
<div className="w-full h-[120px] md:h-[240px] rounded-12 mb-16 overflow-hidden">
|
||||
<Controller
|
||||
control={control}
|
||||
name="cover_image"
|
||||
render={({ field: { onChange, value, onBlur, ref } }) => <CoverImageInput
|
||||
value={value}
|
||||
onBlur={onBlur}
|
||||
onChange={onChange}
|
||||
uploadText='Add a cover image'
|
||||
onChange={e => {
|
||||
onChange(e)
|
||||
}}
|
||||
// uploadText='Add a cover image'
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
@@ -153,11 +157,21 @@ export default function StoryForm(props: Props) {
|
||||
/>
|
||||
</div>
|
||||
|
||||
<TagsInput
|
||||
placeholder="Add up to 5 popular tags..."
|
||||
classes={{ container: 'mt-16' }}
|
||||
<Controller
|
||||
control={control}
|
||||
name="tags"
|
||||
render={({ field: { onChange, value, onBlur } }) => (
|
||||
<TagsInput
|
||||
placeholder="Add up to 5 popular tags..."
|
||||
classes={{ container: 'mt-16' }}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
onBlur={onBlur}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
||||
|
||||
</div>
|
||||
<ContentEditor
|
||||
key={postId}
|
||||
@@ -167,7 +181,7 @@ export default function StoryForm(props: Props) {
|
||||
/>
|
||||
</div>
|
||||
</>}
|
||||
{!editMode && <PreviewPostCard post={{ ...getValues(), cover_image: getValues().cover_image[0] }} />}
|
||||
{!editMode && <PreviewPostCard post={{ ...getValues(), cover_image: getValues('cover_image.url') }} />}
|
||||
<div className="flex gap-16 mt-32">
|
||||
<Button
|
||||
type='submit'
|
||||
|
||||
@@ -4,54 +4,42 @@ import { useRef, useState } from "react";
|
||||
import { ErrorBoundary, withErrorBoundary } from "react-error-boundary";
|
||||
import { FormProvider, NestedValue, Resolver, useForm } from "react-hook-form";
|
||||
import ErrorPage from "src/Components/Errors/ErrorPage/ErrorPage";
|
||||
import { Post_Type } from "src/graphql";
|
||||
import { CreateStoryMutationVariables, Post_Type } from "src/graphql";
|
||||
import { StorageService } from "src/services";
|
||||
import { useAppSelector } from "src/utils/hooks";
|
||||
import { Override } from "src/utils/interfaces";
|
||||
import { imageSchema, tagSchema } from "src/utils/validation";
|
||||
import * as yup from "yup";
|
||||
import DraftsContainer from "../Components/DraftsContainer/DraftsContainer";
|
||||
import ErrorsContainer from "../Components/ErrorsContainer/ErrorsContainer";
|
||||
import StoryForm from "../Components/StoryForm/StoryForm";
|
||||
import styles from './styles.module.scss'
|
||||
|
||||
const FileSchema = yup.lazy((value: string | File[]) => {
|
||||
switch (typeof value) {
|
||||
case 'object':
|
||||
return yup.mixed()
|
||||
.test("fileSize", "File Size is too large", file => file.size <= 5242880)
|
||||
.test("fileType", "Unsupported File Format, only png/jpg/jpeg images are allowed",
|
||||
(file: File) =>
|
||||
["image/jpeg", "image/png", "image/jpg"].includes(file.type))
|
||||
case 'string':
|
||||
return yup.string().url();
|
||||
default:
|
||||
return yup.mixed()
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
const schema = yup.object({
|
||||
title: yup.string().trim().required().min(10, 'Story title must be 2+ words').transform(v => v.replace(/(\r\n|\n|\r)/gm, "")),
|
||||
tags: yup.array().required().min(1, 'Add at least one tag'),
|
||||
body: yup.string().required().min(50, 'Post must contain at least 10+ words'),
|
||||
cover_image: yup.array().of(FileSchema as any)
|
||||
tags: yup.array().of(tagSchema).required().min(1, 'Add at least one tag'),
|
||||
body: yup.string().required("Write some content in the post").min(50, 'Post must contain at least 10+ words'),
|
||||
cover_image: imageSchema.nullable(true),
|
||||
|
||||
}).required();
|
||||
|
||||
|
||||
export interface IStoryFormInputs {
|
||||
id: number | null
|
||||
title: string
|
||||
tags: NestedValue<{ title: string }[]>
|
||||
cover_image: NestedValue<File[]> | NestedValue<string[]>
|
||||
body: string
|
||||
is_published: boolean | null
|
||||
type ApiStoryInput = NonNullable<CreateStoryMutationVariables['data']>;
|
||||
|
||||
export type IStoryFormInputs = {
|
||||
id: ApiStoryInput['id']
|
||||
title: ApiStoryInput['title']
|
||||
body: ApiStoryInput['body']
|
||||
cover_image: NestedValue<NonNullable<ApiStoryInput['cover_image']>> | null
|
||||
tags: NestedValue<ApiStoryInput['tags']>
|
||||
is_published: ApiStoryInput['is_published']
|
||||
}
|
||||
|
||||
|
||||
|
||||
export type CreateStoryType = Override<IStoryFormInputs, {
|
||||
cover_image: ApiStoryInput['cover_image'],
|
||||
tags: { title: string }[]
|
||||
cover_image: File[] | string[]
|
||||
}>
|
||||
|
||||
const storageService = new StorageService<CreateStoryType>('story-edit');
|
||||
@@ -64,13 +52,13 @@ function CreateStoryPage() {
|
||||
story: state.staging.story || storageService.get()
|
||||
}))
|
||||
|
||||
const formMethods = useForm<IStoryFormInputs>({
|
||||
resolver: yupResolver(schema) as Resolver<IStoryFormInputs>,
|
||||
const formMethods = useForm<CreateStoryType>({
|
||||
resolver: yupResolver(schema) as Resolver<CreateStoryType>,
|
||||
shouldFocusError: false,
|
||||
defaultValues: {
|
||||
id: story?.id ?? null,
|
||||
title: story?.title ?? '',
|
||||
cover_image: story?.cover_image ?? [],
|
||||
cover_image: story?.cover_image,
|
||||
tags: story?.tags ?? [],
|
||||
body: story?.body ?? '',
|
||||
is_published: story?.is_published ?? false,
|
||||
|
||||
@@ -31,7 +31,8 @@ export default function StoryPageContent({ story }: Props) {
|
||||
<Card id="content" onlyMd className="relative max">
|
||||
{story.cover_image &&
|
||||
<img src={story.cover_image}
|
||||
className='w-full object-cover rounded-12 md:rounded-16 mb-16'
|
||||
className='w-full h-[120px] md:h-[240px] object-cover rounded-12 mb-16'
|
||||
// className='w-full object-cover rounded-12 md:rounded-16 mb-16'
|
||||
alt="" />}
|
||||
<div className="flex flex-col gap-24 relative">
|
||||
{curUser?.id === story.author.id && <Menu
|
||||
|
||||
@@ -28,7 +28,7 @@ export const useUpdateStory = (story: Story) => {
|
||||
const handleEdit = () => {
|
||||
dispatch(stageStory({
|
||||
...story,
|
||||
cover_image: story.cover_image ? [story.cover_image] : []
|
||||
cover_image: story.cover_image ? { id: null, name: null, url: story.cover_image } : null,
|
||||
}))
|
||||
|
||||
navigate("/blog/create-post?type=story")
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import { SubmitHandler, useForm } from "react-hook-form"
|
||||
import { Controller, SubmitHandler, useForm } from "react-hook-form"
|
||||
import { useUpdateProfileAboutMutation, useMyProfileAboutQuery, UpdateProfileAboutMutationVariables, UserBasicInfoFragmentDoc } from "src/graphql";
|
||||
import { NotificationsService } from "src/services/notifications.service";
|
||||
import * as yup from "yup";
|
||||
import { yupResolver } from "@hookform/resolvers/yup";
|
||||
import Avatar from "src/features/Profiles/Components/Avatar/Avatar";
|
||||
import { useAppDispatch, usePrompt } from "src/utils/hooks";
|
||||
import SaveChangesCard from "../SaveChangesCard/SaveChangesCard";
|
||||
import { toast } from "react-toastify";
|
||||
@@ -12,15 +11,18 @@ import NotFoundPage from "src/features/Shared/pages/NotFoundPage/NotFoundPage";
|
||||
import { setUser } from "src/redux/features/user.slice";
|
||||
import UpdateProfileAboutTabSkeleton from "./BasicProfileInfoTab.Skeleton";
|
||||
import { useApolloClient } from "@apollo/client";
|
||||
import AvatarInput from "src/Components/Inputs/FilesInputs/AvatarInput/AvatarInput";
|
||||
import { imageSchema } from "src/utils/validation";
|
||||
|
||||
interface Props {
|
||||
}
|
||||
|
||||
type IFormInputs = NonNullable<UpdateProfileAboutMutationVariables['data']>;
|
||||
|
||||
|
||||
const schema: yup.SchemaOf<IFormInputs> = yup.object({
|
||||
name: yup.string().trim().required().min(2),
|
||||
avatar: yup.string().url().required(),
|
||||
avatar: imageSchema.required(),
|
||||
bio: yup.string().ensure(),
|
||||
email: yup.string().email().ensure(),
|
||||
github: yup.string().ensure(),
|
||||
@@ -55,8 +57,10 @@ const schema: yup.SchemaOf<IFormInputs> = yup.object({
|
||||
|
||||
export default function BasicProfileInfoTab() {
|
||||
|
||||
const { register, formState: { errors, isDirty, }, handleSubmit, reset } = useForm<IFormInputs>({
|
||||
defaultValues: {},
|
||||
const { register, formState: { errors, isDirty, }, handleSubmit, reset, control } = useForm<IFormInputs>({
|
||||
defaultValues: {
|
||||
|
||||
},
|
||||
resolver: yupResolver(schema),
|
||||
mode: 'onBlur',
|
||||
});
|
||||
@@ -65,7 +69,7 @@ export default function BasicProfileInfoTab() {
|
||||
const profileQuery = useMyProfileAboutQuery({
|
||||
onCompleted: data => {
|
||||
if (data.me)
|
||||
reset(data.me)
|
||||
reset({ ...data.me, avatar: { url: data.me.avatar } })
|
||||
}
|
||||
})
|
||||
const [mutate, mutationStatus] = useUpdateProfileAboutMutation();
|
||||
@@ -107,7 +111,7 @@ export default function BasicProfileInfoTab() {
|
||||
onCompleted: ({ updateProfileDetails: data }) => {
|
||||
if (data) {
|
||||
dispatch(setUser(data))
|
||||
reset(data);
|
||||
reset({ ...data, avatar: { url: data.avatar } });
|
||||
apolloClient.writeFragment({
|
||||
id: `User:${data?.id}`,
|
||||
data,
|
||||
@@ -123,12 +127,21 @@ export default function BasicProfileInfoTab() {
|
||||
})
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-24">
|
||||
<Card className="md:col-span-2" defaultPadding={false}>
|
||||
<div className="bg-gray-600 relative h-[160px] rounded-t-16">
|
||||
<div className="absolute left-24 bottom-0 translate-y-1/2">
|
||||
<Avatar src={profileQuery.data.me.avatar} width={120} />
|
||||
<Controller
|
||||
control={control}
|
||||
name="avatar"
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<AvatarInput value={value} onChange={onChange} width={120} />
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="p-16 md:p-24 mt-64">
|
||||
@@ -148,29 +161,14 @@ export default function BasicProfileInfoTab() {
|
||||
{errors.name && <p className="input-error">
|
||||
{errors.name.message}
|
||||
</p>}
|
||||
<p className="text-body5 mt-16 font-medium">
|
||||
Avatar
|
||||
</p>
|
||||
<div className="input-wrapper mt-8 relative">
|
||||
<input
|
||||
|
||||
type='text'
|
||||
className="input-text"
|
||||
placeholder='https://images.com/my-avatar.jpg'
|
||||
{...register("avatar")}
|
||||
/>
|
||||
</div>
|
||||
{errors.avatar && <p className="input-error">
|
||||
{errors.avatar.message}
|
||||
</p>}
|
||||
<p className="text-body5 mt-16 font-medium">
|
||||
Bio
|
||||
</p>
|
||||
<div className="input-wrapper mt-8 relative">
|
||||
<textarea
|
||||
|
||||
rows={3}
|
||||
className="input-text !p-20"
|
||||
rows={4}
|
||||
className="input-text"
|
||||
placeholder='Tell others a little bit about yourself'
|
||||
{...register("bio")}
|
||||
/>
|
||||
|
||||
@@ -2,23 +2,16 @@ import { motion } from 'framer-motion'
|
||||
import { ModalCard, modalCardVariants } from 'src/Components/Modals/ModalsContainer/ModalsContainer'
|
||||
import { useEffect, useState } from "react"
|
||||
import { Grid } from "react-loader-spinner";
|
||||
import { CONSTS } from "src/utils";
|
||||
import { QRCodeSVG } from 'qrcode.react';
|
||||
import Button from "src/Components/Button/Button";
|
||||
import { FiCopy } from "react-icons/fi";
|
||||
import useCopyToClipboard from "src/utils/hooks/useCopyToClipboard";
|
||||
import { useApolloClient } from '@apollo/client';
|
||||
import { IoClose } from 'react-icons/io5';
|
||||
import { fetchLnurlAuth } from 'src/api/auth';
|
||||
|
||||
|
||||
|
||||
const fetchLnurlAuth = async () => {
|
||||
const res = await fetch(CONSTS.apiEndpoint + '/get-login-url?action=link', {
|
||||
credentials: 'include'
|
||||
})
|
||||
const data = await res.json()
|
||||
return data;
|
||||
}
|
||||
|
||||
const useLnurlQuery = () => {
|
||||
const [loading, setLoading] = useState(true)
|
||||
|
||||
Reference in New Issue
Block a user