Skip to content

Commit

Permalink
Merge pull request #53 from relaxxpls/master
Browse files Browse the repository at this point in the history
[v1.6.0] Contact us page and success toasts
  • Loading branch information
relaxxpls authored Jan 4, 2022
2 parents 02f6f51 + 11e69f6 commit 00754c6
Show file tree
Hide file tree
Showing 26 changed files with 392 additions and 198 deletions.
11 changes: 6 additions & 5 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# ? React env vars
REACT_APP_VERSION=$npm_package_version
REACT_APP_NAME=$npm_package_name

# * Current environment, choices: ['development', 'production']
NODE_ENV=development
# api config
REACT_APP_API_HOST=

# * For absolute imports
NODE_PATH='src/'
REACT_APP_SSO_CLIENT_ID=
REACT_APP_SSO_REDIRECT_URI=http://localhost:3000/login
8 changes: 8 additions & 0 deletions src/assets/svgs/logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
89 changes: 73 additions & 16 deletions src/components/Contact/ContactContainer.jsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,90 @@
// import { useState } from 'react'
import { Input } from 'antd'
import { useState } from 'react'
import styled from 'styled-components/macro'

import { ButtonSquare, InputSquared, TextAreaSquared } from 'components/shared'
import { DeveloperList } from 'components/Contact'
import {
ButtonSquare,
Form,
PageHeading,
PageTitle,
toast,
} from 'components/shared'
import { API } from 'config'

const ContactContainer = () => {
// const [state, setState] = useState(initalState)
const [loading, setLoading] = useState(false)
const [form] = Form.useForm()

// const handleInput = (e) => {
// const inputName = e.currentTarget.name
// const value = e.currentTarget.value
// setState((prev) => ({ ...prev, [inputName]: value }))
// }
const handleSubmit = async (payload) => {
try {
setLoading(true)
await API.feedback.share({ payload })
toast({ status: 'success', content: 'Feedback shared successfully' })
form.resetFields()
} catch (error) {
toast({ status: 'error', content: error })
} finally {
setLoading(false)
}
}

return (
<ContainerForm>
<InputSquared placeholder="Subject" type="text" />
<>
<PageHeading>
<PageTitle>Contact us</PageTitle>
</PageHeading>

<TextAreaSquared placeholder="Message" />
<StyledForm
form={form}
name="contact"
onFinish={handleSubmit}
layout="vertical"
requiredMark={false}
>
<Form.Item
name="subject"
label="Subject"
rules={[
{ required: true, message: 'Subject is required.' },
{ min: 3, message: 'Subject must be atleast 3 characters.' },
{ max: 100, message: 'Subject must be atmost 100 characters.' },
]}
>
<Input placeholder="Type something..." />
</Form.Item>

<ButtonSquare type="submit">Send Message</ButtonSquare>
</ContainerForm>
<Form.Item name="message" label="Message">
<Input.TextArea
autoSize={{ minRows: 1, maxRows: 10 }}
placeholder="Type something..."
rules={[
{ max: 1000, message: 'Message must be atmost 1000 characters.' },
]}
/>
</Form.Item>

<div style={{ display: 'inline' }}>
<ButtonSquare type="primary" htmlType="submit" loading={loading}>
Submit
</ButtonSquare>
</div>
</StyledForm>

<DeveloperList />
</>
)
}

const ContainerForm = styled.form`
export default ContactContainer

const StyledForm = styled(Form)`
display: flex;
flex-direction: column;
gap: 1.5rem;
padding: 1rem;
background: ${({ theme }) => theme.secondary};
border-radius: 0.5rem;
box-shadow: 0 0 0.5rem rgb(0 0 0 / 50%);
margin-bottom: 1rem;
`

export default ContactContainer
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useDispatch, useSelector } from 'react-redux'
import styled from 'styled-components/macro'

import { useResponsive } from 'hooks'
import { selectIsDropdownActive, toggleDropdown } from 'store/settingsSlice'
import { selectIsDropdownActive, setDropdown } from 'store/settingsSlice'

const FilterFloatButton = () => {
const [Icon, setIcon] = useState(Filter)
Expand All @@ -13,12 +13,12 @@ const FilterFloatButton = () => {
const dispatch = useDispatch()

// ? show or hide dropdown filters state
const toggleFilter = () => dispatch(toggleDropdown(!isDropdownActive))
const toggleFilter = () => dispatch(setDropdown(!isDropdownActive))

// ? dropdown disabled on wide screens
useEffect(() => {
if (isDesktop) {
dispatch(toggleDropdown(false))
dispatch(setDropdown(false))
setIcon(null)
} else {
setIcon(isDropdownActive ? X : Filter)
Expand Down
11 changes: 4 additions & 7 deletions src/components/CourseReview/CourseReviewContainer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const nestComments = (commentsList) => {
})

commentsList.forEach((comment) => {
if (comment.parent !== null) {
if (comment.parent !== null && commentsMap[comment.parent]) {
if (commentsMap[comment.parent].children === undefined)
commentsMap[comment.parent].children = []
commentsMap[comment.parent].children.push(comment)
Expand Down Expand Up @@ -77,17 +77,14 @@ const CourseReviewContainer = () => {
}
}

const createContent = async (review) => {
const createContent = async ({ body }) => {
try {
const response = await API.reviews.create({
payload: {
course: code,
parent: null,
body: review,
},
payload: { course: code, parent: null, body },
})

handleUpdateContent({ id: null, payload: { ...response, children: [] } })
toast({ status: 'success', content: 'Successfully posted review' })
} catch (error) {
toast({ status: 'error', content: error })
}
Expand Down
10 changes: 6 additions & 4 deletions src/components/CourseReview/CourseReviewItem.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,13 @@ const CourseReviewItem = ({ content, updateContent, depth }) => {
const showEditForm = () =>
isOwner && (action === 'edit' ? setAction(null) : setAction('edit'))

const handleUpdate = async (body) => {
const handleUpdate = async ({ body }) => {
try {
const payload = { ...content, body }
await API.reviews.update({ id: content.id, payload })

updateContent({ id: content.id, payload })
setAction(null)
toast({ status: 'success', content: 'Successfully updated content' })
} catch (error) {
toast({ status: 'error', content: error })
}
Expand All @@ -71,21 +71,23 @@ const CourseReviewItem = ({ content, updateContent, depth }) => {
try {
await API.reviews.delete({ id: content.id })
updateContent({ id: content.id, payload: null })
toast({ status: 'success', content: 'Successfully deleted content' })
} catch (error) {
toast({ status: 'error', content: error })
}
}

const handleCreateChild = async (reply) => {
const handleCreateChild = async ({ body }) => {
try {
const response = await API.reviews.create({
payload: {
course: content.course,
parent: content.id,
body: reply,
body,
status: false,
},
})
toast({ status: 'success', content: 'Successfully replied' })

const payload = content
if (payload?.children) payload.children.push(response)
Expand Down
113 changes: 84 additions & 29 deletions src/components/CourseReview/Editor.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,20 @@ import ReactQuill from 'react-quill'
import { useSelector } from 'react-redux'
import styled from 'styled-components/macro'

import { ButtonSquare, Comment, toast, UserAvatar } from 'components/shared'
import {
ButtonSquare,
Comment,
Form,
toast,
UserAvatar,
} from 'components/shared'
import { selectUserProfile } from 'store/userSlice'

import reviewTemplate from './reviewTemplate'

const formats = [
'header',
'font',
'size',
'code',
'bold',
'italic',
'underline',
Expand Down Expand Up @@ -65,48 +70,98 @@ const CustomToolbar = ({ templateHandler }) => (
</Toolbar>
)

export const QuillEditor = ({
value,
onChange,
placeholder,
templateHandler,
validate,
}) => {
const handleChange = async (content, delta, source, editor) => {
validate(editor.getText().length)
onChange(content)
}

return (
<>
<CustomToolbar templateHandler={templateHandler} />
<StyledReactQuill
formats={formats}
modules={modules}
onChange={handleChange}
value={value}
placeholder={placeholder}
/>
</>
)
}

export const Editor = ({
onSubmit,
initialValue = '',
submitText = 'Post',
templateHandler,
}) => {
const [content, setContent] = useState(initialValue)
const [loading, setLoading] = useState(false)
const handleChange = (value) => setContent(value)
const [form] = Form.useForm()

const handleSubmit = async () => {
setLoading(true)
const handleSubmit = async (values) => {
try {
await onSubmit(content)
setContent(initialValue)
setLoading(true)
const errors = form.getFieldError('body')
if (errors.length) throw new Error(errors[0])

await onSubmit(values)
form.resetFields()
form.setFields([{ name: 'body', errors: [] }])
} catch (error) {
toast({ status: 'error', content: error })
} finally {
setLoading(false)
}
}

const validate = (length) => {
if (length <= 10) {
form.setFields([
{
name: 'body',
errors: ['Review must be atleast 10 characters long.'],
},
])
} else if (length > 3000) {
form.setFields([
{
name: 'body',
errors: ['Review must be atmost 3000 characters long.'],
},
])
} else {
form.setFields([{ name: 'body', errors: [] }])
}
}
// git imp "Add "
return (
<>
<CustomToolbar templateHandler={templateHandler} />
<StyledReactQuill
placeholder="Write your review here..."
onChange={handleChange}
value={content}
formats={formats}
modules={modules}
/>

<ButtonSquare
type="primary"
htmlType="submit"
onClick={handleSubmit}
loading={loading}
>
{submitText}
</ButtonSquare>
</>
<Form
layout="vertical"
form={form}
onFinish={handleSubmit}
initialValues={{ body: initialValue }}
>
<Form.Item name="body">
<QuillEditor
templateHandler={templateHandler}
placeholder="Write your review here..."
validate={validate}
/>
</Form.Item>

<Form.Item>
<ButtonSquare type="primary" htmlType="submit" loading={loading}>
{submitText}
</ButtonSquare>
</Form.Item>
</Form>
)
}

Expand All @@ -122,7 +177,7 @@ export const ReviewEditor = ({ ...editorProps }) => {
alt="Profile picture"
/>
}
content={<Editor visible {...editorProps} />}
content={<Editor {...editorProps} />}
/>
)
}
Expand Down
Loading

0 comments on commit 00754c6

Please sign in to comment.