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

fix: new source and squad writing form issues #2895

Merged
merged 5 commits into from
Apr 2, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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
1 change: 1 addition & 0 deletions packages/shared/src/components/modals/NewSourceModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,7 @@ export default function NewSourceModal(props: ModalProps): ReactElement {
<Modal
{...modalProps}
formProps={{
title: 'Suggest new source',
form: linkHasFeed ? 'select-feed' : 'submit-source',
copy: { right: linkHasFeed ? 'Submit for review' : 'Check link' },
rightButtonProps: {
Expand Down
91 changes: 69 additions & 22 deletions packages/shared/src/components/squads/Details.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ import React, { FormEvent, ReactElement, useContext, useState } from 'react';
import classNames from 'classnames';
import { ClientError } from 'graphql-request';
import { useMutation } from '@tanstack/react-query';
import { useRouter } from 'next/router';
import { Button, ButtonColor, ButtonVariant } from '../buttons/Button';
import { TextField } from '../fields/TextField';
import { AtIcon, CameraIcon, SquadIcon } from '../icons';
import { AtIcon, CameraIcon, SourceIcon, SquadIcon } from '../icons';
import Textarea from '../fields/Textarea';
import ImageInput from '../fields/ImageInput';
import { cloudinary } from '../../lib/image';
Expand All @@ -16,8 +17,11 @@ import { IconSize } from '../Icon';
import { SourceMemberRole } from '../../graphql/sources';
import { Radio } from '../fields/Radio';
import { squadsPublicWaitlist } from '../../lib/constants';
import { ManageSquadPageFooter } from './utils';
import { ManageSquadPageFooter, SquadSubTitle, SquadTitle } from './utils';
import AuthContext from '../../contexts/AuthContext';
import ConditionalWrapper from '../ConditionalWrapper';
import { useViewSize, ViewSize } from '../../hooks';
import { FormWrapper } from '../fields/form';

const squadImageId = 'squad_image_file';

Expand All @@ -27,6 +31,8 @@ interface SquadDetailsProps {
form: Partial<SquadForm>;
createMode: boolean;
onRequestClose?: () => void;
onCanSubmit?: (canSubmit: boolean) => void;
canSubmit?: (canSubmit: boolean) => void;
}

const getFormData = async (
Expand Down Expand Up @@ -101,11 +107,13 @@ export function SquadDetails({
memberPostingRole: initialMemberPostingRole,
memberInviteRole: initialMemberInviteRole,
} = form;
const isMobile = useViewSize(ViewSize.MobileL);
const [activeHandle, setActiveHandle] = useState(handle);
const [imageChanged, setImageChanged] = useState(false);
const [handleHint, setHandleHint] = useState<string>(null);
const [canSubmit, setCanSubmit] = useState(!!name && !!activeHandle);
const [isDescriptionOpen, setDescriptionOpen] = useState(!createMode);
const router = useRouter();
const [memberPostingRole, setMemberPostingRole] = useState(
() => initialMemberPostingRole || SourceMemberRole.Member,
);
Expand Down Expand Up @@ -165,7 +173,41 @@ export function SquadDetails({
};

return (
<>
<ConditionalWrapper
condition={isMobile}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the condition not be isMobile && createMode?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On Edit mode, there should be a "Save" button.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But still in a form wrapper?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes.

wrapper={(component) => (
<FormWrapper
form="squad-form"
copy={{ right: createMode ? 'Create Squad' : 'Save' }}
leftButtonProps={{
onClick: () =>
router.push(createMode ? '/squads' : `/squads/${handle}`),
}}
rightButtonProps={{
disabled: !canSubmit,
variant: ButtonVariant.Primary,
color: createMode ? ButtonColor.Cabbage : undefined,
}}
>
{component}
</FormWrapper>
)}
>
{createMode && (
<div
style={{
backgroundImage: `url(${cloudinary.squads.createSquad})`,
}}
className="mb-6 flex h-52 w-full flex-col items-center justify-center bg-cover bg-center"
>
<SourceIcon size={IconSize.XXXLarge} />
<SquadTitle className="mb-2">Create new Squad</SquadTitle>
<SquadSubTitle>
Create a group where you can learn and interact privately with other
developers around topics that matter to you
</SquadSubTitle>
</div>
)}
<div className={classNames('flex flex-col', className)}>
<form
className="-mb-2 flex flex-col items-center gap-4"
Expand Down Expand Up @@ -286,25 +328,30 @@ export function SquadDetails({
</div>
</form>
</div>
<ManageSquadPageFooter
className={classNames(!createMode && 'px-6', 'mt-auto justify-between')}
>
{createMode && (
<Button onClick={onRequestClose} variant={ButtonVariant.Tertiary}>
Close
</Button>
)}
<Button
variant={ButtonVariant.Primary}
color={createMode ? ButtonColor.Cabbage : undefined}
className={!createMode && 'w-full'}
form="squad-form"
type="submit"
disabled={!canSubmit}
{!isMobile && (
<ManageSquadPageFooter
className={classNames(
!createMode && 'px-6',
'mt-auto justify-between',
)}
>
{createMode ? 'Create Squad' : 'Save'}
</Button>
</ManageSquadPageFooter>
</>
{createMode && (
<Button onClick={onRequestClose} variant={ButtonVariant.Tertiary}>
Close
</Button>
)}
<Button
variant={ButtonVariant.Primary}
color={createMode ? ButtonColor.Cabbage : undefined}
className={!createMode && 'w-full'}
form="squad-form"
type="submit"
disabled={!canSubmit}
>
{createMode ? 'Create Squad' : 'Save'}
</Button>
</ManageSquadPageFooter>
)}
</ConditionalWrapper>
);
}
2 changes: 1 addition & 1 deletion packages/webapp/pages/squads/[handle]/edit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ const EditSquad = ({ handle }: EditSquadPageProps): ReactElement => {
<ManageSquadPageContainer>
<NextSeo {...seo} titleTemplate="%s | daily.dev" noindex nofollow />
<ManageSquadPageMain>
<ManageSquadPageHeader>
<ManageSquadPageHeader className="hidden tablet:flex">
<Button
className="mr-2"
variant={ButtonVariant.Tertiary}
Expand Down
25 changes: 2 additions & 23 deletions packages/webapp/pages/squads/new.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { ReactElement, useContext, useState } from 'react';
import React, { ReactElement, useContext } from 'react';
import { NextSeo, NextSeoProps } from 'next-seo';
import router, { useRouter } from 'next/router';
import { useAuthContext } from '@dailydotdev/shared/src/contexts/AuthContext';
Expand All @@ -9,16 +9,11 @@ import { SquadForm, createSquad } from '@dailydotdev/shared/src/graphql/squads';
import { useBoot } from '@dailydotdev/shared/src/hooks/useBoot';
import { useToastNotification } from '@dailydotdev/shared/src/hooks/useToastNotification';
import { AnalyticsEvent } from '@dailydotdev/shared/src/lib/analytics';
import { SourceIcon } from '@dailydotdev/shared/src/components/icons';
import {
SquadTitle,
SquadSubTitle,
ManageSquadPageContainer,
ManageSquadPageMain,
} from '@dailydotdev/shared/src/components/squads/utils';
import { cloudinary } from '@dailydotdev/shared/src/lib/image';
import { MangeSquadPageSkeleton } from '@dailydotdev/shared/src/components/squads/MangeSquadPageSkeleton';
import { IconSize } from '@dailydotdev/shared/src/components/Icon';
import { ActionType } from '@dailydotdev/shared/src/graphql/actions';
import { useActions } from '@dailydotdev/shared/src/hooks/useActions';
import { getLayout as getMainLayout } from '../../components/layouts/MainLayout';
Expand All @@ -39,9 +34,6 @@ const NewSquad = (): ReactElement => {
const { displayToast } = useToastNotification();
const { addSquad } = useBoot();
const { completeAction } = useActions();
const [form] = useState<Partial<SquadForm>>({
public: false,
});

const onCreate = async (e, newSquadForm: SquadForm) => {
e.preventDefault();
Expand Down Expand Up @@ -79,22 +71,9 @@ const NewSquad = (): ReactElement => {
<ManageSquadPageContainer>
<NextSeo {...seo} titleTemplate="%s | daily.dev" noindex nofollow />
<ManageSquadPageMain>
<div
style={{
backgroundImage: `url(${cloudinary.squads.createSquad})`,
}}
className="mb-6 flex h-52 w-full flex-col items-center justify-center bg-cover"
>
<SourceIcon size={IconSize.XXXLarge} />
<SquadTitle className="mb-2">Create new Squad</SquadTitle>
<SquadSubTitle>
Create a group where you can learn and interact privately with other
developers around topics that matter to you
</SquadSubTitle>
</div>
<SquadDetails
className="p-8 pt-0"
form={form}
form={{ public: false }}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does this setting do?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really sure what happens inside, but I just noticed a local state above and doesn't seem to be changed. Instead I added this inline object over the unnecessary hook.

onRequestClose={handleClose}
onSubmit={onCreate}
createMode
Expand Down