Skip to content

Commit

Permalink
Rip 149 dm ux improvements (#89)
Browse files Browse the repository at this point in the history
* Set the Status Filter for Default Member View

Change default Member Status filter from "Show All" to "Is Raiding"

* Clarify the Raid Role Dropdown Copy

Modified button text for clarity.

* Add Copy Raid ID Button

Fixes the previous implementation of Copy in InfoStack, which was not
clickable.

The workaround for truncating the Raid ID in RaidDetailsCard was the
following snippet using minWidth, which could probably be done better.

<Stack justify='center' minWidth={'0.5'}>

* Add Min Width on Consultation/Raid Details section

* Clarify the Count on Raids, Consultations, Members

* Show Project Specs when no link is available

Also addresses "Specs value is missing or missing NA option"

* Make Raid Links match default font and size

Fix: `InfoStack` with link is different size/font to text infos

* Improve Status Update readability via layout

Also solves a bug where revealed status updates could overflow the
width of the container.

Called "Better status update layout" in RIP 149 notes

* Clarify the Count on Applications

* task: removed "Dashboard" text from /

* Fix Client Email overlapping with adjacent text

* WIP multi-select raid roles required mutation

* Working update raid roles multi-select

* Standardize role remove across 2 files

* Note: need to let react hook form manage state

* Style update role section

* add escrow zap

* separate escrow utils & gql

* update gnosis

* QA on escrow zap

* update walletconnect & wagmi, use pnpm

# Conflicts:
#	libs/dm-hooks/src/useEscrowZap.ts

---------

Co-authored-by: Derrek <[email protected]>
Co-authored-by: memosys <[email protected]>
  • Loading branch information
3 people authored Nov 6, 2023
1 parent 2f8dff6 commit d76add2
Show file tree
Hide file tree
Showing 15 changed files with 267 additions and 117 deletions.
26 changes: 17 additions & 9 deletions apps/frontend/components/InfoStack.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import React from 'react';
import {
Stack,
Text,
Link as ChakraLink,
HStack,
Icon,
Tooltip,
useClipboard,
Button,
} from '@raidguild/design-system';
import { FaExternalLinkAlt, FaInfoCircle, FaCopy } from 'react-icons/fa';
import Link from './ChakraNextLink';
Expand All @@ -32,7 +32,7 @@ const InfoStack: React.FC<InfoStackProps> = ({
const copyText = useClipboard(details);

return (
<Stack justify='center'>
<Stack justify='center' minWidth={'0.5'}>
<HStack>
<Text color='white' fontSize='sm'>
{label}
Expand All @@ -49,19 +49,27 @@ const InfoStack: React.FC<InfoStackProps> = ({
{link ? (
<Link href={link} isExternal>
<HStack>
<Text color='white' fontSize='lg' fontWeight='medium'>
<Text color='white' fontSize='lg' fontWeight='medium' isTruncated>
{details}
</Text>
<Icon as={FaExternalLinkAlt} />
</HStack>
</Link>
) : copy ? (
<HStack>
<Text color='white' fontSize='lg' fontWeight='medium'>
{details}
</Text>
<Icon as={FaCopy} onClick={copyText.onCopy} />
</HStack>
<Tooltip label={`Copy ${label}`} size='sm' hasArrow>
<Button
variant='unstyled'
onClick={copyText.onCopy}
height={'-webkit-fit-content'}
>
<HStack>
<Text color='white' fontSize='lg' fontWeight='medium' isTruncated>
{details}
</Text>
<Icon as={FaCopy} />
</HStack>
</Button>
</Tooltip>
) : (
<Text color='white' fontSize='lg' fontWeight='medium'>
{details}
Expand Down
30 changes: 22 additions & 8 deletions apps/frontend/components/RaidDetailsCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -102,13 +102,25 @@ const RaidDetailsCard: React.FC<RaidProps> = ({
consultation,
}: RaidProps) => {
const keyLinkItems = [
consultation?.link && {
label: 'Project Specs',
details: AVAILABLE_PROJECT_SPECS_DISPLAY(
_.get(consultation, 'availableProjectSpec.availableProjectSpec')
),
link: consultation?.link,
},
// AVAILABLE_PROJECT_SPECS_DISPLAY is not a required field on the
// consultation form, so we handle edge cases here.
// Logic below should be simplified if it ever becomes a required field.
consultation?.link
? {
label: 'Project Specs',
details: AVAILABLE_PROJECT_SPECS_DISPLAY(
_.get(consultation, 'availableProjectSpec.availableProjectSpec') ||
'YES'
),
link: consultation?.link,
}
: {
label: 'Project Specs',
details: AVAILABLE_PROJECT_SPECS_DISPLAY(
_.get(consultation, 'availableProjectSpec.availableProjectSpec') ||
'NONE'
),
},
_.get(consultation, 'consultationHash') && {
label: 'Consultation Hash',
details:
Expand Down Expand Up @@ -258,6 +270,7 @@ const RaidDetailsCard: React.FC<RaidProps> = ({
_.get(raid, 'airtableId') ||
_.get(raid, 'v1Id') ||
_.get(raid, 'id'),
copy: true,
},
_.get(raid, 'escrowIndex') && {
label: 'Escrow Index',
Expand All @@ -277,7 +290,7 @@ const RaidDetailsCard: React.FC<RaidProps> = ({
];

return (
<Card variant='filled' padding={2}>
<Card variant='filled' padding={2} minWidth={'lg'}>
<Accordion defaultIndex={[0]} allowMultiple w='100%'>
{_.map(panels, (panel, index) => {
if (_.isEmpty(_.get(panel, 'items'))) return null;
Expand Down Expand Up @@ -311,6 +324,7 @@ const RaidDetailsCard: React.FC<RaidProps> = ({
label={_.get(item, 'label')}
details={_.get(item, 'details')}
link={_.get(item, 'link')}
copy={_.get(item, 'copy')}
key={_.get(item, 'label')}
/>
))}
Expand Down
145 changes: 95 additions & 50 deletions apps/frontend/components/RaidPartyInfo/RaidPartyButtons.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
/* eslint-disable react/no-unstable-nested-components */
// TODO fix these
import { useState } from 'react';
import _ from 'lodash';
import { useSession } from 'next-auth/react';
import { FiPlus, FiX } from 'react-icons/fi';
import { Controller, useForm } from 'react-hook-form';
import { Option } from '@raidguild/design-system/dist/components/forms/CreatableSelect/CreatableSelect';
import {
VStack,
HStack,
Expand All @@ -12,18 +13,21 @@ import {
Box,
Icon,
Flex,
Select,
} from '@raidguild/design-system';
import { FiPlus, FiX } from 'react-icons/fi';
import {
memberDisplayName,
GUILD_CLASS_DISPLAY,
GUILD_CLASS_OPTIONS,
IMember,
IRaid,
IRoleRemoveMany,
IRoleRequiredInsert,
memberDisplayName,
membersExceptRaidParty,
SIDEBAR_ACTION_STATES,
rolesExceptRequiredRoles,
SIDEBAR_ACTION_STATES,
} from '@raidguild/dm-utils';
import { useRaidPartyAdd, useAddRolesRequired } from '@raidguild/dm-hooks';
import { useRaidPartyAdd, useUpdateRolesRequired } from '@raidguild/dm-hooks';

type RaidPartyButtonsProps = {
raid?: Partial<IRaid>;
Expand All @@ -34,8 +38,6 @@ type RaidPartyButtonsProps = {
setButton?: (button: string) => void;
};

// TODO swap for better selects

const RaidPartyButtons = ({
raid,
cleric,
Expand All @@ -47,40 +49,66 @@ const RaidPartyButtons = ({
const { data: session } = useSession();
const token = _.get(session, 'token');
const localMembers = membersExceptRaidParty(members, raidParty, cleric);
const requiredRoles: string[] = _.map(
_.get(raid, 'raidsRolesRequired'),
'role'
);
const rolesFormDefaultValues = _.map(requiredRoles, (role) => ({
value: role,
label: GUILD_CLASS_DISPLAY[role],
}));

const localRoles = rolesExceptRequiredRoles(
_.keys(GUILD_CLASS_DISPLAY),
raid
);
const [roleToAdd, setRoleToAdd] = useState<string>();
const localForm = useForm({
mode: 'all',
});
const { control, handleSubmit } = localForm;
const [selectedRoleOptions, setSelectedRoleOptions] = useState<Option>();
const [raiderToAdd, setRaiderToAdd] = useState<string>();

const { mutateAsync: updateRolesRequired } = useAddRolesRequired({
const { mutateAsync: updateRolesRequired } = useUpdateRolesRequired({
token,
});
const { mutateAsync: addRaider } = useRaidPartyAdd({ token });

const submitAddRole = async () => {
// TODO check against current localRoles
const submitUpdateRoles = async () => {
const selectedRoleValues: string[] = _.map(
selectedRoleOptions,
(selection: Option) => selection.value
);
const rolesAdded: string[] = _.difference(
selectedRoleValues,
requiredRoles
);
const rolesRemoved: string[] = _.difference(
requiredRoles,
selectedRoleValues
);
const raidId = _.get(raid, 'id');

const insertRoles: IRoleRequiredInsert[] = _.map(rolesAdded, (role) => ({
raid_id: raidId,
role,
}));
const rolesRemovedWhere: IRoleRemoveMany = {
_and: {
role: { _in: rolesRemoved },
raid_id: { _eq: raidId },
},
};
await updateRolesRequired({
raidId: _.get(raid, 'id'),
role: roleToAdd,
insertRoles: insertRoles,
where: rolesRemovedWhere,
});

setTimeout(() => {
setRoleToAdd(undefined);
setButton(SIDEBAR_ACTION_STATES.none);
}, 250);
};

// TODO clear click for selecting roles to remove in one save
// const clearRoleClick = () => {
// if (clearRoles) {
// // setClearRoles(false);
// setLocalRoles(_.get(raid, 'rolesRequired'));
// } else {
// // setClearRoles(true);
// }
// };

const submitAddRaider = async () => {
await addRaider({
raidId: _.get(raid, 'id'),
Expand All @@ -99,7 +127,7 @@ const RaidPartyButtons = ({
leftIcon={<FiPlus />}
onClick={() => setButton(SIDEBAR_ACTION_STATES.select)}
>
Add Role or Raider
Add Raider or Update Roles
</Button>
);

Expand All @@ -118,37 +146,54 @@ const RaidPartyButtons = ({
variant='outline'
onClick={() => {
setButton(SIDEBAR_ACTION_STATES.role);
setRoleToAdd(_.keys(GUILD_CLASS_DISPLAY)[0]);
}}
>
Add Role
Update Roles
</Button>
</HStack>
);

const SelectRole = () => (
<Flex justify='space-between' gap={1} w='100%'>
<IconButton
variant='outline'
icon={<Icon as={FiX} color='primary.500' />}
aria-label='Clear Set Role Required for Raid'
onClick={() => {
setButton(SIDEBAR_ACTION_STATES.none);
setRoleToAdd(undefined);
}}
/>
<ChakraSelect
onChange={(e) => setRoleToAdd(e.target.value)}
value={roleToAdd}
>
{_.map(localRoles, (key: string) => (
<option value={key} key={key}>
{GUILD_CLASS_DISPLAY[key]}
</option>
))}
</ChakraSelect>
<Button onClick={submitAddRole}>Add</Button>
</Flex>
// Wrap this whole component in a Chakra component to make it fill the width of its container div

<Box width='full'>
<form onSubmit={handleSubmit(submitUpdateRoles)}>
<Controller
name='updateRolesSelect'
control={control}
render={({ field }) => (
<Select
{...field}
variant='outline'
isMulti
placeholder='Select Roles'
isClearable={false}
options={GUILD_CLASS_OPTIONS}
defaultValue={rolesFormDefaultValues}
localForm={localForm}
// Note: Below warning suggests this is a workaround to react hook form's intended use
// "Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?"
onChange={(values) => {
setSelectedRoleOptions(values);
}}
value={selectedRoleOptions}
/>
)}
/>
<HStack justify={'center'} gap={1} w='100%'>
<Button
variant={'outline'}
aria-label='Clear Set Role Required for Raid'
onClick={() => {
setButton(SIDEBAR_ACTION_STATES.none);
}}
>
Cancel
</Button>
<Button type='submit'>Update</Button>
</HStack>
</form>
</Box>
);

// TODO handle loading a bit better
Expand Down
37 changes: 11 additions & 26 deletions apps/frontend/components/RaidPartyInfo/RaidPartyCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -132,34 +132,19 @@ const RaidPartyCard = ({
const saveUpdatedRoles = async () => {
const rolesRemoved = _.difference(roles, localRoles);
// const rolesAdded = _.difference(localRoles, roles);
if (!rolesRemoved) return;

let rolesRemovedWhere = null;
// setClearRoles(false);
if (!_.isEmpty(rolesRemoved)) {
if (rolesRemoved.length === 1) {
rolesRemovedWhere = {
_and: {
raid_id: _.get(raid, 'id'),
role: rolesRemoved[0],
},
};
}
if (rolesRemoved.length > 1) {
rolesRemovedWhere = {
_or: rolesRemoved.map((role: string) => ({
_and: {
raid_id: _.get(raid, 'id'),
role,
},
})),
};
}
if (!rolesRemovedWhere) return;
const rolesRemovedWhere = {
_and: {
role: { _in: rolesRemoved },
raid_id: { _eq: _.get(raid, 'id') },
},
};

await removeRolesRequired({
where: rolesRemovedWhere,
});
}
// setClearRoles(false);
await removeRolesRequired({
where: rolesRemovedWhere,
});
};

const GeneralCard = ({ button, children }: GeneralCardProps) => (
Expand Down
4 changes: 2 additions & 2 deletions apps/frontend/components/RaidUpdates.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const RaidUpdate: React.FC<RaidUpdateProps> = ({
>
<Flex
gap={4}
direction={['column', null, null, 'row']}
direction={['column', null, null, null]}
alignItems='flex-start'
justifyContent='space-between'
width='100%'
Expand All @@ -37,7 +37,7 @@ const RaidUpdate: React.FC<RaidUpdateProps> = ({
color='white'
as='p'
fontSize='md'
maxWidth={['95%', null, null, '60%']}
maxWidth={['95%', null, null, null]}
>
{update}
</Text>
Expand Down
Loading

0 comments on commit d76add2

Please sign in to comment.