Skip to content
Merged

Dev #109

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions frontend/src/pages/HomePage/components/Main/Main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,14 @@ import { RootState } from '@app/store'
import { useLazyMezonAppControllerSearchMezonAppQuery } from '@app/services/api/mezonApp/mezonApp'
import { IMezonAppStore } from '@app/store/mezonApp'
import { useMezonAppSearch } from '@app/hook/useSearch'
import { useSearchParams } from 'react-router-dom'
import { useNavigate, useSearchParams } from 'react-router-dom'
import { toast } from 'react-toastify'
import { ApiError } from '@app/types/API.types'
import { IMainProps } from '@app/types/Main.type'

const pageOptions = [5, 10, 15]
function Main({ isSearchPage = false }: IMainProps) {
const navigate = useNavigate()
const [botPerPage, setBotPerPage] = useState<number>(pageOptions[0])
const [page, setPage] = useState<number>(1)
const [isOpen, setIsOpen] = useState<boolean>(false)
Expand All @@ -35,7 +36,11 @@ function Main({ isSearchPage = false }: IMainProps) {
useEffect(() => {
if (isError && error) {
const apiError = error as ApiError
toast.error(apiError?.data?.message[0])
if (apiError?.status === 404 || apiError?.data?.statusCode === 404) {
navigate('/*');
} else {
toast.error(apiError?.data?.message);
}
}
}, [isError, error])

Expand Down Expand Up @@ -93,7 +98,7 @@ function Main({ isSearchPage = false }: IMainProps) {
<div>
<MtbTypography variant='h3'>Mezon Bots</MtbTypography>
<MtbTypography variant='h5' weight='normal'>
Showing 1 of {mezonApp.totalPages} page
Showing 1 of {mezonApp.totalPages ?? 0 } page
</MtbTypography>
</div>
<SingleSelect
Expand Down
104 changes: 43 additions & 61 deletions frontend/src/pages/NewBotPage/components/AddBotForm/AddBotForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,55 +12,47 @@ import { RootState } from '@app/store'
import { ILinkTypeStore } from '@app/store/linkType'
import { ITagStore } from '@app/store/tag'
import { ApiError } from '@app/types/API.types'
import { IAddBotFormProps, ISocialLinksData } from '@app/types/Botcard.types'
import { IAddBotFormProps } from '@app/types/Botcard.types'
import { Checkbox, Form, Input, Select, TagProps } from 'antd'
import TextArea from 'antd/es/input/TextArea'
import { useEffect, useMemo, useState } from 'react'
import { Controller, useFormContext } from 'react-hook-form'
import { useMemo, useState } from 'react'
import { Controller, useFieldArray, useFormContext } from 'react-hook-form'
import { useSelector } from 'react-redux'
import { useNavigate, useParams } from 'react-router-dom'
import { toast } from 'react-toastify'
function AddBotForm({ isEdit }: IAddBotFormProps) {
const {
control,
handleSubmit,
watch,
setValue,
formState: { errors }
} = useFormContext<CreateMezonAppRequest>()
const [addBot] = useMezonAppControllerCreateMezonAppMutation()
const navigate = useNavigate()
const [updateBot] = useMezonAppControllerUpdateMezonAppMutation()
const { tagList } = useSelector<RootState, ITagStore>((s) => s.tag)
const { linkTypeList } = useSelector<RootState, ILinkTypeStore>((s) => s.link)
const socialLinksInMezonAppDetails = watch('socialLinks')
const [selectedSocialLink, setSelectedSocialLink] = useState<string>('') // holds selected link type id
const [socialLinksData, setSocialLinksData] = useState<ISocialLinksData[]>([])
const { fields: socialLinksData, append, remove } = useFieldArray({
control,
name: 'socialLinks'
});
const [socialLinkUrl, setSocialLinkUrl] = useState<string>('')
const [dropdownOpen, setDropdownOpen] = useState(false);

const { botId } = useParams()

useEffect(() => {
if (!socialLinksInMezonAppDetails?.length) return
const formattedLinksData = socialLinksInMezonAppDetails.map(link => {
const urlObj = new URL(link.url || '');
return {
icon: link?.icon || '',
name: `${urlObj.host}`.toUpperCase(),
url: `${urlObj.pathname.slice(1)}`,
id: link?.linkTypeId || '',
siteName: `${urlObj.protocol}//${urlObj.host}/`
}
})
setSocialLinksData(formattedLinksData)
}, [socialLinksInMezonAppDetails])

const onSubmit = async (data: CreateMezonAppRequest) => {
try {
const formattedSocialLinks = socialLinksData.map((link) => ({
url: `${link.siteName}${link.url}`,
linkTypeId: link.id
}))
const formattedSocialLinks = socialLinksData.map((link) => {
const selectedLink = optionsLink?.find((item) => item.value === link.linkTypeId)
if (!selectedLink) return link
const siteName = selectedLink.siteName
return {
url: `${siteName}${link.url}`,
linkTypeId: selectedLink.value,
}
})

const { ...restData } = data

Expand All @@ -72,7 +64,7 @@ function AddBotForm({ isEdit }: IAddBotFormProps) {
const response = await addBot({ createMezonAppRequest: addBotData }).unwrap()
toast.success('Add new bot success')
if (response.id) {
navigate(`/${response.id}`)
navigate(`/bot/${response.id}`)
}
return
}
Expand Down Expand Up @@ -118,7 +110,7 @@ function AddBotForm({ isEdit }: IAddBotFormProps) {
label: `${item.icon} ${item.name}`,
value: item.id,
icon: item.icon,
siteName: `https://${item.name.toLowerCase()}.com/`
siteName: `https://${item.name.toLowerCase()}.com/`,
}))
}, [linkTypeList])

Expand All @@ -128,39 +120,23 @@ function AddBotForm({ isEdit }: IAddBotFormProps) {
if (!selectedSocialLink || !trimmedUrl) return
// get selectedLink in optionsLink
const selectedLink = optionsLink?.find((item) => item.value === selectedSocialLink)
// if selectedLink in socialLinksData then return
if (socialLinksData.some((link) => link.name === selectedLink?.label)) return
if (!selectedLink) return

const defaultSocialLink = {
icon: selectedLink?.icon || '',
name: selectedLink?.label || '',
icon: selectedLink.icon,
url: `${trimmedUrl}`,
id: selectedLink?.value || '',
siteName: selectedLink?.siteName || ''
linkTypeId: selectedLink?.value,
}
// add new links to the links list
setSocialLinksData([...socialLinksData, defaultSocialLink])
append(defaultSocialLink)
setSocialLinkUrl('')
setSelectedSocialLink('')
}

const removeLink = (id: string) => {
setSocialLinksData(socialLinksData.filter((link) => link.id !== id))
}

const handleSocialLinkUrlChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setSocialLinkUrl(e.target.value)
}

const editSocialLink = (e: React.ChangeEvent<HTMLInputElement>, id: string) => {
const index = socialLinksData.findIndex((link) => link.id === id)
if (index === -1) return

const newLinks = [...socialLinksData]
newLinks[index].url = e.target.value
setSocialLinksData(newLinks)
}

const handleSelectTag = (value: string[]) => {
console.log(`selected ${value}`)
}
Expand Down Expand Up @@ -350,20 +326,26 @@ function AddBotForm({ isEdit }: IAddBotFormProps) {
</div>
</div>
{!!socialLinksData.length &&
socialLinksData.map((link, index) => (
<div key={index} className='mt-4 flex gap-4'>
<Input
className='flex-1 border p-2 rounded'
value={link.url}
placeholder='Enter link'
prefix={`${link?.icon} ${link.siteName}`}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => editSocialLink(e, link?.id)}
/>
<Button onClick={() => removeLink(link?.id)} customClassName='!w-[70px]'>
Delete
</Button>
</div>
))}
socialLinksData.map((link, index) => {
const selectedLink = optionsLink?.find((item) => item.value === link.linkTypeId)
const siteName = selectedLink?.siteName || '';
return (
<div key={index} className='mt-4 flex gap-4'>
<Input
onChange={(e) => {
setValue(`socialLinks.${index}.url`, e.target.value)
}}
className='flex-1 border p-2 rounded'
value={link.url}
placeholder='Enter link'
prefix={`${link?.icon} ${siteName}`}
/>
<Button onClick={() => remove(index)} customClassName='!w-[70px]'>
Delete
</Button>
</div>
)
})}
</FormField>
<div className='flex !justify-end pt-8 gap-4 items-center'>
<Button color='default' customClassName='w-[200px] !text-blue-500'>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/services/api/mezonApp/mezonApp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ export type App = {
}
export type SocialLinkDto = {
url?: string
linkTypeId?: string
linkTypeId: string
icon?: string
}
export type CreateMezonAppRequest = {
Expand Down
8 changes: 0 additions & 8 deletions frontend/src/types/Botcard.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,6 @@ export interface IBotCardProps {
data?: GetMezonAppDetailsResponse
}

export interface ISocialLinksData {
icon: string
name: string
url: string
id: string
siteName: string
}

export interface ICompactBotCardProps {
data?: GetRelatedMezonAppResponse
isPublic?: boolean
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/validations/addBot.validations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ export const ADD_BOT_SCHEMA = yup.object({
tagIds: yup.array().of(yup.string().required()).min(1, 'At least one tag is required').strict().defined(),
socialLinks: yup.array().of(
yup.object().shape({
url: yup.string().url('Invalid URL').test('url-length', 'URL is too long', (val) => val.length <= 2082),
url: yup.string().test('url-length', 'URL is too long', (val) => (val || "").length <= 2082),
linkTypeId: yup.string().required('Link Type is required')
})
).min(1, 'At least one social link is required')
)
})