Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/adding gig board #9

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
30 changes: 25 additions & 5 deletions src/components/Form/ServiceForm.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useWeb3Modal } from '@web3modal/react';
import { BigNumberish, ethers, FixedNumber, Signer, Wallet } from 'ethers';
import { BigNumberish, ethers, FixedNumber } from 'ethers';
import { ErrorMessage, Field, Form, Formik } from 'formik';
import { useContext, useState } from 'react';
import { useRouter } from 'next/router';
Expand Down Expand Up @@ -35,7 +35,12 @@ const initialValues: IFormValues = {
rateAmount: 0,
};

function ServiceForm() {
interface IServiceFormProps {
onChange?: (event: any) => void;
onSuccess?: () => void;
}

function ServiceForm(props: IServiceFormProps) {
const config = useConfig();
const chainId = useChainId();

Expand Down Expand Up @@ -132,6 +137,7 @@ function ServiceForm() {
cid,
signature,
);
console.log('no active delegate', tx);
}

const newId = await createMultiStepsTransactionToast(
Expand All @@ -149,9 +155,10 @@ function ServiceForm() {
setSubmitting(false);
resetForm();
if (newId) {
router.push(`/dashboard/services/${newId}`);
props?.onSuccess ? props.onSuccess() : router.push(`/dashboard/services/${newId}`);
}
} catch (error) {
console.log('tx error: ', error);
showErrorTransactionToast(error);
}
} else {
Expand All @@ -161,12 +168,16 @@ function ServiceForm() {

return (
<Formik initialValues={initialValues} onSubmit={onSubmit} validationSchema={validationSchema}>
{({ isSubmitting, setFieldValue }) => (
{({ isSubmitting, setFieldValue, handleChange }) => (
<Form>
<div className='grid grid-cols-1 gap-6 border border-gray-700 rounded-xl p-6 bg-endnight'>
<label className='block'>
<span className='text-gray-100'>Title</span>
<Field
onChange={(e: any) => {
handleChange(e);
props.onChange && props.onChange({ [e?.target?.name]: e?.target?.value });
}}
type='text'
id='title'
name='title'
Expand All @@ -181,6 +192,10 @@ function ServiceForm() {
<label className='block'>
<span className='text-gray-100'>About</span>
<Field
onChange={(e: any) => {
handleChange(e);
props.onChange && props.onChange({ [e?.target?.name]: e?.target?.value });
}}
as='textarea'
id='about'
name='about'
Expand All @@ -204,6 +219,10 @@ function ServiceForm() {
<label className='block flex-1 mr-4'>
<span className='text-gray-100'>Amount</span>
<Field
onChange={(e: any) => {
handleChange(e);
props.onChange && props.onChange({ [e?.target?.name]: e?.target?.value });
}}
type='number'
id='rateAmount'
name='rateAmount'
Expand All @@ -222,10 +241,11 @@ function ServiceForm() {
name='rateToken'
className='mt-1 mb-1 block w-full rounded-xl border border-gray-700 bg-midnight shadow-sm focus:ring-opacity-50'
placeholder=''
onChange={(e: { target: { value: string } }) => {
onChange={(e: { target: { value: string; name: string } }) => {
const token = allowedTokenList.find(token => token.address === e.target.value);
setSelectedToken(token);
setFieldValue('rateToken', e.target.value);
props.onChange && props.onChange({ [e?.target?.name]: e?.target?.value });
}}>
<option value=''>Select a token</option>
{allowedTokenList.map((token, index) => (
Expand Down
2 changes: 1 addition & 1 deletion src/components/Form/SubmitButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ function SubmitButton({
openConnectModal();
}}
type='button'
className='grow px-5 py-2 rounded-xl bg-redpraha text-white hover:bg-midnight '>
className='grow px-5 py-2 rounded-xl bg-redpraha text-white hover:bg-midnight'>
{'Connect first'}
</button>
)}
Expand Down
5 changes: 5 additions & 0 deletions src/components/Form/skills-input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ import { XMarkIcon } from '@heroicons/react/24/outline';
export function SkillsInput({
initialValues,
entityId,
onSelectedSkills,
}: {
initialValues?: string;
entityId: string;
onSelectedSkills?: (skills: string[]) => void;
}) {
const formikProps = useFormikContext();
const { skills: filteredSkills, fetchData: refreshSkills, query, setQuery } = useWorkxSkills();
Expand All @@ -20,6 +22,9 @@ export function SkillsInput({
const selectSkill = (value: string) => {
const newSkills = [...allSkills, value];
setAllSkills(newSkills);

// call this function in case consumer wants to hook into it
onSelectedSkills && onSelectedSkills(newSkills);
setSelectedSkill('');
setQuery('');
formikProps.setFieldValue(entityId, newSkills.toString());
Expand Down
8 changes: 7 additions & 1 deletion src/components/Layout/SideLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,18 @@ import { useRouter } from 'next/router';

function SideLink({ children, href }: { children: React.ReactNode; href: string }) {
const router = useRouter();
const isActive = (path: string) => {
if (router.asPath === path) return true;
if (router.asPath.startsWith(path + '/')) return true;
return false;
};

const isDashboard = href == '/dashboard';
let className = isDashboard
? router.asPath === href
? 'bg-redpraha text-white'
: 'text-zinc-100 hover:bg-midnight'
: router.asPath.includes(href)
: isActive(href)
? 'bg-redpraha text-white'
: 'text-zinc-100 hover:bg-midnight';

Expand Down
7 changes: 7 additions & 0 deletions src/components/Layout/navigation.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
BriefcaseIcon,
ChatBubbleBottomCenterIcon,
DeviceTabletIcon,
UserGroupIcon,
UserIcon,
} from '@heroicons/react/24/outline';
Expand All @@ -10,4 +11,10 @@ export const navigation = [
{ name: 'Chat', href: '/dashboard/messaging', icon: ChatBubbleBottomCenterIcon, current: false },
{ name: 'Gigs', href: '/dashboard/services', icon: BriefcaseIcon, current: false },
{ name: 'Talents', href: '/dashboard/talents', icon: UserGroupIcon, current: false },
{
name: 'My Gig Board',
href: '/dashboard/services-embed',
icon: DeviceTabletIcon,
current: false,
},
];
39 changes: 39 additions & 0 deletions src/components/ServicesEmbed/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React from 'react';
import useServices from '../../hooks/useServices';
import { ServiceStatusEnum } from '../../types';
import Loading from '../Loading';
import ServiceItem from '../ServiceItem';

interface IServicesEmbedProps {
buyerId: string;
status: ServiceStatusEnum;
title: string;
}
const ServicesEmbed = (props: IServicesEmbedProps) => {
const { services, loading } = useServices(props.status, props.buyerId);

if (loading) {
return (
<div className='flex justify-center items-center gap-10 flex-col pb-5 mt-5'>
<Loading />
</div>
);
}

if (services.length === 0) {
return <h1 className='text-title text-4xl mb-4 text-center mt-3'>You have no gigs</h1>;
}

return (
<div>
<h1 className='text-title text-4xl mb-4 text-center'>{props.title}</h1>
{services.map(_service => (
<div className='my-2' key={_service.id}>
<ServiceItem service={_service} />
</div>
))}
</div>
);
};

export default ServicesEmbed;
126 changes: 126 additions & 0 deletions src/pages/dashboard/services-embed/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import { useContext, useState } from 'react';
import Image from 'next/image';
import { useRouter } from 'next/router';
import { parseRateAmount } from '../../../utils/web3';
import { useChainId } from '../../../hooks/useChainId';
import useAllowedTokens from '../../../hooks/useAllowedTokens';
import StarterKitContext from '../../../context/starterKit';
import Steps from '../../../components/Steps';
import ServiceForm from '../../../components/Form/ServiceForm';
import { formatDate } from '../../../utils/dates';
import { renderTokenAmountFromConfig } from '../../../utils/conversion';

interface ILiveServiceContent {
title?: string;
about?: string;
rateAmount?: string;
rateToken?: string;
}

const ServicesEmbedCreate = () => {
const [liveServiceContent, setLiveServiceContent] = useState<ILiveServiceContent>({
title: 'Enter a title',
rateToken: '0x0000000000000000000000000000000000000000',
rateAmount: '0',
});

const chainId = useChainId();
const allowedTokenList = useAllowedTokens();
const { user } = useContext(StarterKitContext);
const router = useRouter();
const navigateToServicesEmbedSettings = () => router.push('/dashboard/services-embed/settings');

const handleServiceFormInput = async (event: ILiveServiceContent) => {
// TODO: move this to an async function expression
if (event.rateAmount) {
if (liveServiceContent?.rateToken) {
const token = allowedTokenList.find(
token => token.address === liveServiceContent.rateToken,
);

if (token) {
const _parsedRateAmount = await parseRateAmount(
event.rateAmount.toString(),
liveServiceContent.rateToken,
token.decimals,
);

setLiveServiceContent({
...liveServiceContent,
rateAmount: _parsedRateAmount.toString(),
});
}
}
} else {
setLiveServiceContent({ ...liveServiceContent, ...event });
}
};

if (!user) {
return <Steps />;
}

return (
<div className='max-w-7xl mx-auto text-gray-200 sm:px-4 lg:px-0'>
<p className='flex items-center text-2xl font-medium tracking-wider mb-8 border-b w-full border-gray-700'>
Post your First Gig
</p>
<div className='grid grid-cols-2 gap-2'>
<div>
<ServiceForm
onSuccess={navigateToServicesEmbedSettings}
onChange={handleServiceFormInput}
/>
<div className='mt-4 grid grid-cols-2'>
<div />
<button
type='submit'
className='rounded-xl text-white'
onClick={navigateToServicesEmbedSettings}>
{'>'} Skip and configure your board
</button>
</div>
</div>
<div>
<div className='flex flex-row gap-2 rounded-xl p-4 border border-gray-700 text-white bg-endnight'>
<div className='flex flex-col items-top justify-between gap-4 w-full'>
<div className='flex flex-col justify-start items-start gap-4'>
<div className='flex items-center justify-start'>
<Image
src={`/images/default-avatar-${Number(user?.id) % 9}.jpeg`}
className='w-10 mr-4 rounded-full'
width={50}
height={50}
alt='default avatar'
/>
<div className='flex flex-col'>
<p className='font-medium break-all'>{liveServiceContent?.title}</p>
<p className='text-xs text-gray-400'>
created by {user?.handle} the {formatDate(Number(Date.now()) * 1000)}
</p>
</div>
</div>
</div>
<div>
<p>{liveServiceContent.about}</p>
</div>
<div className='flex flex-row gap-4 justify-between items-center border-t border-gray-700 pt-4'>
{liveServiceContent?.rateToken && liveServiceContent?.rateAmount && (
<p className='text-gray-300 font-bold'>
{renderTokenAmountFromConfig(
chainId,
liveServiceContent.rateToken,
liveServiceContent.rateAmount,
)}
</p>
)}
</div>
</div>
</div>
</div>
</div>
</div>
);
};

export default ServicesEmbedCreate;
Loading