@homefile/components-v2 1.0.15 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/dist/assets/locales/en/index.json +23 -1
  2. package/dist/components/headers/TabsHeader.js +1 -1
  3. package/dist/components/myProfile/MyProfileBody.d.ts +1 -1
  4. package/dist/components/myProfile/MyProfileBody.js +6 -2
  5. package/dist/components/myProfile/index.d.ts +1 -0
  6. package/dist/components/myProfile/index.js +1 -0
  7. package/dist/components/myProfile/permissions/ActionCheckbox.d.ts +2 -0
  8. package/dist/components/myProfile/permissions/ActionCheckbox.js +6 -0
  9. package/dist/components/myProfile/permissions/ActionLabel.d.ts +5 -0
  10. package/dist/components/myProfile/permissions/ActionLabel.js +17 -0
  11. package/dist/components/myProfile/permissions/PermissionsBanner.d.ts +5 -0
  12. package/dist/components/myProfile/permissions/PermissionsBanner.js +23 -0
  13. package/dist/components/myProfile/permissions/RoleButton.d.ts +2 -0
  14. package/dist/components/myProfile/permissions/RoleButton.js +11 -0
  15. package/dist/components/myProfile/permissions/RolePermissionsTab.d.ts +2 -0
  16. package/dist/components/myProfile/permissions/RolePermissionsTab.js +19 -0
  17. package/dist/components/myProfile/permissions/index.d.ts +5 -0
  18. package/dist/components/myProfile/permissions/index.js +5 -0
  19. package/dist/helpers/HomeRoles.helper.d.ts +3 -1
  20. package/dist/helpers/HomeRoles.helper.js +6 -1
  21. package/dist/helpers/myProfile/RolePermissions.helper.d.ts +2 -0
  22. package/dist/helpers/myProfile/RolePermissions.helper.js +72 -0
  23. package/dist/helpers/myProfile/index.d.ts +1 -0
  24. package/dist/helpers/myProfile/index.js +1 -0
  25. package/dist/hooks/myProfile/index.d.ts +1 -0
  26. package/dist/hooks/myProfile/index.js +1 -0
  27. package/dist/hooks/myProfile/useRolePermissionsTab.d.ts +11 -0
  28. package/dist/hooks/myProfile/useRolePermissionsTab.js +64 -0
  29. package/dist/index.d.ts +2 -2
  30. package/dist/index.js +2 -2
  31. package/dist/interfaces/myProfile/MyProfileBody.interface.d.ts +5 -4
  32. package/dist/interfaces/myProfile/index.d.ts +1 -0
  33. package/dist/interfaces/myProfile/index.js +1 -0
  34. package/dist/interfaces/myProfile/permissions/ActionCheckbox.interface.d.ts +8 -0
  35. package/dist/interfaces/myProfile/permissions/ActionCheckbox.interface.js +1 -0
  36. package/dist/interfaces/myProfile/permissions/RoleButton.interface.d.ts +7 -0
  37. package/dist/interfaces/myProfile/permissions/RoleButton.interface.js +1 -0
  38. package/dist/interfaces/myProfile/permissions/RolePermissionsTab.interface.d.ts +12 -0
  39. package/dist/interfaces/myProfile/permissions/RolePermissionsTab.interface.js +1 -0
  40. package/dist/interfaces/myProfile/permissions/index.d.ts +3 -0
  41. package/dist/interfaces/myProfile/permissions/index.js +3 -0
  42. package/dist/mocks/myProfile/Permissions.mock.d.ts +2 -0
  43. package/dist/mocks/myProfile/Permissions.mock.js +68 -0
  44. package/dist/mocks/myProfile/index.d.ts +1 -0
  45. package/dist/mocks/myProfile/index.js +1 -0
  46. package/dist/stories/myProfile/MyProfilePanel.stories.js +3 -4
  47. package/dist/stories/myProfile/permissions/RolePermissionsTab.stories.d.ts +5 -0
  48. package/dist/stories/myProfile/permissions/RolePermissionsTab.stories.js +16 -0
  49. package/package.json +1 -1
  50. package/src/assets/locales/en/index.json +23 -1
  51. package/src/components/headers/TabsHeader.tsx +1 -0
  52. package/src/components/myProfile/MyProfileBody.tsx +6 -1
  53. package/src/components/myProfile/index.ts +1 -0
  54. package/src/components/myProfile/permissions/ActionCheckbox.tsx +22 -0
  55. package/src/components/myProfile/permissions/ActionLabel.tsx +18 -0
  56. package/src/components/myProfile/permissions/PermissionsBanner.tsx +35 -0
  57. package/src/components/myProfile/permissions/RoleButton.tsx +39 -0
  58. package/src/components/myProfile/permissions/RolePermissionsTab.tsx +111 -0
  59. package/src/components/myProfile/permissions/index.ts +5 -0
  60. package/src/helpers/HomeRoles.helper.ts +16 -1
  61. package/src/helpers/myProfile/RolePermissions.helper.ts +74 -0
  62. package/src/helpers/myProfile/index.ts +1 -0
  63. package/src/hooks/myProfile/index.ts +2 -1
  64. package/src/hooks/myProfile/useRolePermissionsTab.ts +104 -0
  65. package/src/index.ts +2 -1
  66. package/src/interfaces/myProfile/MyProfileBody.interface.ts +5 -4
  67. package/src/interfaces/myProfile/index.ts +1 -0
  68. package/src/interfaces/myProfile/permissions/ActionCheckbox.interface.ts +9 -0
  69. package/src/interfaces/myProfile/permissions/RoleButton.interface.ts +8 -0
  70. package/src/interfaces/myProfile/permissions/RolePermissionsTab.interface.ts +19 -0
  71. package/src/interfaces/myProfile/permissions/index.ts +3 -0
  72. package/src/mocks/myProfile/Permissions.mock.ts +70 -0
  73. package/src/mocks/myProfile/index.ts +2 -1
  74. package/src/stories/myProfile/MyProfilePanel.stories.tsx +8 -8
  75. package/src/stories/myProfile/permissions/RolePermissionsTab.stories.tsx +23 -0
@@ -1 +1,2 @@
1
+ export * from './Permissions.mock';
1
2
  export * from './Receipts.mock';
@@ -1 +1,2 @@
1
+ export * from './Permissions.mock';
1
2
  export * from './Receipts.mock';
@@ -1,9 +1,8 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { t } from 'i18next';
3
2
  import { Box, Divider, DrawerBody } from '@chakra-ui/react';
4
- import { ActiveSubscription, CancelAccount, CreditCardContainer, CreditCardError, EmailPermissions, MonthlyCharge, MyProfileBody, MyProfileHeader, MyProfilePanel, NewCreditCard, NewCreditCardHeader, PaymentReceipts, RightPanel, TwoFactorSetting, UserDetails, } from '../../components';
3
+ import { ActiveSubscription, CancelAccount, CreditCardContainer, CreditCardError, MonthlyCharge, MyProfileBody, MyProfileHeader, MyProfilePanel, NewCreditCard, NewCreditCardHeader, PaymentReceipts, RightPanel, RolePermissionsTab, TwoFactorSetting, UserDetails, } from '../../components';
5
4
  import { action } from '@storybook/addon-actions';
6
- import { menuMock, receiptsMock } from '../../mocks';
5
+ import { featuresSelectedMock, menuMock, receiptsMock } from '../../mocks';
7
6
  import { useState } from 'react';
8
7
  export default {
9
8
  title: 'Components/MyProfile',
@@ -15,5 +14,5 @@ export const MyProfilePanelComponent = () => {
15
14
  const handleCloseNewCreditCardPanel = () => setIsNewCreditCardPanelOpen(false);
16
15
  const handleOpenNewCreditCardPanel = () => setIsNewCreditCardPanelOpen(true);
17
16
  const handleError = () => setHasError(true);
18
- return (_jsxs(_Fragment, { children: [_jsx(RightPanel, { isOpen: true, onClose: action('onCloseClick'), children: _jsxs(MyProfilePanel, { children: [_jsx(MyProfileHeader, { onClose: action('onCloseClick') }), _jsx(MyProfileBody, { isLoading: false, account: _jsxs(_Fragment, { children: [_jsx(ActiveSubscription, { nextCharge: "2024-12-01", subscriptionPrice: 36, totalStorage: 2, totalUsed: 1, availableStorage: 200, state: 'trial' }), _jsx(Divider, { width: "calc(100% - 26px)", mx: "auto" }), _jsx(MonthlyCharge, { additionalPrice: 36, monthlyCharge: 36, monthDate: "03/01/2023", nextCharge: "01/12/2024", taxPercentage: 8.5, taxValue: 3.06, subtotal: 36.0 }), _jsx(CancelAccount, { label: "Contact Homefile", onClick: action('onCancelAccountClick') })] }), details: _jsxs(_Fragment, { children: [_jsx(UserDetails, { email: "gary.edmunds@gmail.com", firstName: "Gary", lastName: "Edmunds", onSave: action('onSaveClick'), bg: "#4CC35A" }), _jsx(TwoFactorSetting, { email: "gary.edmunds@gmail.com", sms: "2032409108", onChange: action('on2FAChangeClick'), onSave: action('onSaveClick'), defaultValue: "email", twoFactor: 'active' })] }), email: _jsx(EmailPermissions, { initialPermissions: ['Promotions', 'Homefile News'], emailPermissions: t('myProfile.email.permissions').split(', '), onSubmit: (data) => action('onDeleteCard')(data) }), payment: _jsxs(Box, { bg: "lightBlue.2", h: "inherit", children: [_jsx(CreditCardContainer, { cardNumber: "1234 5678 9012 3456", brand: "visa", onAddCard: action('onAddCard'), onDeleteCard: handleOpenNewCreditCardPanel, onSubmit: (data) => action('onDeleteCard')(data), cardHolder: "Gary Edmunds", cvv: "123", expirationMonth: "12", expirationYear: "2024" }), _jsx(PaymentReceipts, { receipts: receiptsMock, menuItems: menuMock })] }) })] }) }), _jsx(RightPanel, { isOpen: isNewCreditCardPanelOpen, onClose: handleCloseNewCreditCardPanel, children: _jsxs(MyProfilePanel, { children: [_jsx(MyProfileHeader, { onClose: handleCloseNewCreditCardPanel }), _jsxs(DrawerBody, { p: "0", children: [_jsx(NewCreditCardHeader, { onClick: handleCloseNewCreditCardPanel }), hasError && _jsx(CreditCardError, {}), _jsx(NewCreditCard, { hasError: hasError, onSubmit: handleError })] })] }) })] }));
17
+ return (_jsxs(_Fragment, { children: [_jsx(RightPanel, { isOpen: true, onClose: action('onCloseClick'), children: _jsxs(MyProfilePanel, { children: [_jsx(MyProfileHeader, { onClose: action('onCloseClick') }), _jsx(MyProfileBody, { isLoading: false, account: _jsxs(_Fragment, { children: [_jsx(ActiveSubscription, { nextCharge: "2024-12-01", subscriptionPrice: 36, totalStorage: 2, totalUsed: 1, availableStorage: 200, state: 'trial' }), _jsx(Divider, { width: "calc(100% - 26px)", mx: "auto" }), _jsx(MonthlyCharge, { additionalPrice: 36, monthlyCharge: 36, monthDate: "03/01/2023", nextCharge: "01/12/2024", taxPercentage: 8.5, taxValue: 3.06, subtotal: 36.0 }), _jsx(CancelAccount, { label: "Contact Homefile", onClick: action('onCancelAccountClick') })] }), details: _jsxs(_Fragment, { children: [_jsx(UserDetails, { email: "gary.edmunds@gmail.com", firstName: "Gary", lastName: "Edmunds", onSave: action('onSaveClick'), bg: "#4CC35A" }), _jsx(TwoFactorSetting, { email: "gary.edmunds@gmail.com", sms: "2032409108", onChange: action('on2FAChangeClick'), onSave: action('onSaveClick'), defaultValue: "email", twoFactor: 'active' })] }), payment: _jsxs(Box, { bg: "lightBlue.2", h: "inherit", children: [_jsx(CreditCardContainer, { cardNumber: "1234 5678 9012 3456", brand: "visa", onAddCard: action('onAddCard'), onDeleteCard: handleOpenNewCreditCardPanel, onSubmit: (data) => action('onDeleteCard')(data), cardHolder: "Gary Edmunds", cvv: "123", expirationMonth: "12", expirationYear: "2024" }), _jsx(PaymentReceipts, { receipts: receiptsMock, menuItems: menuMock })] }), rolePermissions: _jsx(RolePermissionsTab, { selected: featuresSelectedMock, onSelect: action('onSelect') }) })] }) }), _jsx(RightPanel, { isOpen: isNewCreditCardPanelOpen, onClose: handleCloseNewCreditCardPanel, children: _jsxs(MyProfilePanel, { children: [_jsx(MyProfileHeader, { onClose: handleCloseNewCreditCardPanel }), _jsxs(DrawerBody, { p: "0", children: [_jsx(NewCreditCardHeader, { onClick: handleCloseNewCreditCardPanel }), hasError && _jsx(CreditCardError, {}), _jsx(NewCreditCard, { hasError: hasError, onSubmit: handleError })] })] }) })] }));
19
18
  };
@@ -0,0 +1,5 @@
1
+ import { Meta } from '@storybook/react';
2
+ import { RolePermissionsTabI } from '../../../interfaces';
3
+ declare const _default: Meta<RolePermissionsTabI>;
4
+ export default _default;
5
+ export declare const RolePermissionsTabComponent: (args: RolePermissionsTabI) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,16 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { Box } from '@chakra-ui/react';
3
+ import { action } from '@storybook/addon-actions';
4
+ import { RolePermissionsTab } from '../../../components';
5
+ import { featuresSelectedMock } from '../../../mocks';
6
+ export default {
7
+ title: 'Components/MyProfile',
8
+ component: RolePermissionsTab,
9
+ args: {
10
+ selected: featuresSelectedMock,
11
+ onSelect: action('onSelect'),
12
+ },
13
+ };
14
+ export const RolePermissionsTabComponent = (args) => {
15
+ return (_jsx(Box, { w: ['full', '500px'], bg: "white", children: _jsx(RolePermissionsTab, Object.assign({}, args)) }));
16
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@homefile/components-v2",
3
- "version": "1.0.15",
3
+ "version": "1.1.0",
4
4
  "author": "Homefile",
5
5
  "license": "UNLICENSED",
6
6
  "typings": "dist/index.d.ts",
@@ -448,6 +448,13 @@
448
448
  "title": "My Homes"
449
449
  },
450
450
  "myProfile": {
451
+ "actions": {
452
+ "add": "Add",
453
+ "can": "Can",
454
+ "edit": "Edit",
455
+ "delete": "Delete",
456
+ "view": "View"
457
+ },
451
458
  "account": {
452
459
  "cancel": "Cancel Account",
453
460
  "cancelInfo": "To cancel your Homefile account, please contact Homefile below.",
@@ -477,6 +484,20 @@
477
484
  "receiptsTitle": "Receipts",
478
485
  "toDelete": "To delete a card, you must first add a new card."
479
486
  },
487
+ "permissions": {
488
+ "contributor": {
489
+ "description": "Can view, add, and edit the information when you share a home.",
490
+ "title": "Contributor Permissions"
491
+ },
492
+ "manager": {
493
+ "description": "Can view, add, and edit all home information within a home.",
494
+ "title": "Manager Permissions"
495
+ },
496
+ "member": {
497
+ "description": "Can only view information when you share a home.",
498
+ "title": "Member Permissions"
499
+ }
500
+ },
480
501
  "placeholders": {
481
502
  "cardHolder": "Name on card",
482
503
  "cardNumber": "Card number",
@@ -491,7 +512,8 @@
491
512
  "tab2": "Subscription",
492
513
  "tab3": "Payment",
493
514
  "tab4": "Email",
494
- "tab5": "Sharing"
515
+ "tab5": "Sharing",
516
+ "tab6": "Role Permissions"
495
517
  }
496
518
  },
497
519
  "newPassword": {
@@ -23,6 +23,7 @@ export const TabsHeader = ({
23
23
  onChange={onChange}
24
24
  index={tabIndex}
25
25
  defaultIndex={defaultIndex}
26
+ h="100%"
26
27
  >
27
28
  <Box bg="lightBlue.2">
28
29
  <Flex justify="space-between">
@@ -10,6 +10,7 @@ export const MyProfileBody = ({
10
10
  email,
11
11
  isLoading,
12
12
  payment,
13
+ rolePermissions,
13
14
  }: MyProfileBodyI) => {
14
15
  const tabs = [
15
16
  {
@@ -28,7 +29,11 @@ export const MyProfileBody = ({
28
29
  label: t('myProfile.tabs.tab4'),
29
30
  component: email,
30
31
  },
31
- ]
32
+ {
33
+ label: t('myProfile.tabs.tab6'),
34
+ component: rolePermissions,
35
+ },
36
+ ].filter((tab) => tab.component)
32
37
  return (
33
38
  <DrawerBody p="0">
34
39
  {isLoading ? (
@@ -1,6 +1,7 @@
1
1
  export * from './email'
2
2
  export * from './details'
3
3
  export * from './payment'
4
+ export * from './permissions'
4
5
  export * from './AddCreditCard'
5
6
  export * from './BillingAddress'
6
7
  export * from './CancelAccount'
@@ -0,0 +1,22 @@
1
+ import { Stack, Checkbox } from '@chakra-ui/react'
2
+ import { ActionLabel } from '@/components'
3
+ import { ActionCheckboxI } from '@/interfaces'
4
+
5
+ export const ActionCheckbox = ({
6
+ action,
7
+ isChecked,
8
+ isDisabled,
9
+ label,
10
+ onChange,
11
+ }: ActionCheckboxI) => {
12
+ return (
13
+ <Stack spacing="1" align="center" w="33px">
14
+ {label && <ActionLabel label={label} />}
15
+ <Checkbox
16
+ isChecked={isChecked}
17
+ onChange={() => onChange(action)}
18
+ isDisabled={isDisabled}
19
+ />
20
+ </Stack>
21
+ )
22
+ }
@@ -0,0 +1,18 @@
1
+ import { Text, TextProps } from '@chakra-ui/react'
2
+
3
+ export interface ActionLabelI extends TextProps {
4
+ label: string
5
+ }
6
+
7
+ export const ActionLabel = ({ label, ...props }: ActionLabelI) => {
8
+ return (
9
+ <Text
10
+ fontSize="10px"
11
+ fontWeight="semibold"
12
+ textTransform="uppercase"
13
+ {...props}
14
+ >
15
+ {label}
16
+ </Text>
17
+ )
18
+ }
@@ -0,0 +1,35 @@
1
+ import { t } from 'i18next'
2
+ import { RoleType, homeRoles } from '@/helpers'
3
+ import { Stack, Text } from '@chakra-ui/react'
4
+
5
+ export interface PermissionsBannerI {
6
+ role: RoleType
7
+ }
8
+
9
+ export const PermissionsBanner = ({ role }: PermissionsBannerI) => {
10
+ const bgColor = homeRoles[role].bg
11
+ const { title, description } = textsByRole[role as keyof typeof textsByRole]
12
+ return (
13
+ <Stack spacing="1" bg={bgColor} px="base" py="6">
14
+ <Text fontWeight="semibold" color="neutral.white">
15
+ {title}
16
+ </Text>
17
+ <Text color="neutral.white">{description}</Text>
18
+ </Stack>
19
+ )
20
+ }
21
+
22
+ const textsByRole = {
23
+ member: {
24
+ title: t('myProfile.permissions.member.title'),
25
+ description: t('myProfile.permissions.member.description'),
26
+ },
27
+ contributor: {
28
+ title: t('myProfile.permissions.contributor.title'),
29
+ description: t('myProfile.permissions.contributor.description'),
30
+ },
31
+ manager: {
32
+ title: t('myProfile.permissions.manager.title'),
33
+ description: t('myProfile.permissions.manager.description'),
34
+ },
35
+ }
@@ -0,0 +1,39 @@
1
+ import { homeRoles } from '@/helpers'
2
+ import { RoleButtonI } from '@/interfaces'
3
+ import { Center, Text } from '@chakra-ui/react'
4
+
5
+ export const RoleButton = ({
6
+ role,
7
+ onClick,
8
+ isSelected,
9
+ showBorder,
10
+ }: RoleButtonI) => {
11
+ const bgColor = homeRoles[role].bg
12
+ const borderColor = showBorder ? 'lightBlue.2' : 'transparent'
13
+ return (
14
+ <Center
15
+ as="button"
16
+ w="62px"
17
+ bg={isSelected ? 'lightGreen.1' : 'neutral.white'}
18
+ transition="all 0.4s"
19
+ _hover={{
20
+ bg: 'lightGreen.1',
21
+ cursor: 'pointer',
22
+ }}
23
+ onClick={onClick}
24
+ >
25
+ <Center py="base" w="40px" borderY="1px solid" borderColor={borderColor}>
26
+ <Center bg={bgColor} borderRadius="4px" h="26px" w="26px">
27
+ <Text
28
+ fontWeight="semibold"
29
+ color={'neutral.white'}
30
+ fontSize="md"
31
+ textTransform="uppercase"
32
+ >
33
+ {role.charAt(0).toUpperCase()}
34
+ </Text>
35
+ </Center>
36
+ </Center>
37
+ </Center>
38
+ )
39
+ }
@@ -0,0 +1,111 @@
1
+ import { t } from 'i18next'
2
+ import { Box, Center, Flex, Stack, Text } from '@chakra-ui/react'
3
+ import {
4
+ RoleButton,
5
+ PermissionsBanner,
6
+ ActionLabel,
7
+ ActionCheckbox,
8
+ } from '@/components'
9
+
10
+ import { rolePermissions } from '@/helpers'
11
+ import { RolePermissionsTabI } from '@/interfaces'
12
+ import { useRolePermissionsTab } from '@/hooks'
13
+
14
+ export const RolePermissionsTab = ({
15
+ selected,
16
+ onSelect,
17
+ }: RolePermissionsTabI) => {
18
+ const {
19
+ actions,
20
+ callback,
21
+ selectedRole,
22
+ selectedActions,
23
+ handleRoleChange,
24
+ handleFeatureChange,
25
+ handleActionChange,
26
+ } = useRolePermissionsTab({ selected, onSelect })
27
+
28
+ return (
29
+ <Flex h="100%">
30
+ <Box bg="neutral.white">
31
+ <RoleButton
32
+ role="member"
33
+ isSelected={selectedRole === 'member'}
34
+ onClick={() => handleRoleChange('member')}
35
+ showBorder
36
+ />
37
+ <RoleButton
38
+ role="contributor"
39
+ isSelected={selectedRole === 'contributor'}
40
+ onClick={() => handleRoleChange('contributor')}
41
+ />
42
+ <RoleButton
43
+ role="manager"
44
+ isSelected={selectedRole === 'manager'}
45
+ onClick={() => handleRoleChange('manager')}
46
+ showBorder
47
+ />
48
+ </Box>
49
+ <Box>
50
+ <PermissionsBanner role={selectedRole} />
51
+ <Center bg="lightBlue.6" py="base">
52
+ <Flex w="100%">
53
+ <Flex flex="1" gap="base" justify="flex-end" align="start">
54
+ <ActionLabel
55
+ label={t('myProfile.actions.can')}
56
+ color="neutral.white"
57
+ />
58
+ <Box w="1px" bg="neutral.white" h="100%" />
59
+ </Flex>
60
+ <Flex flex="1" justify="space-evenly">
61
+ {actions.map((action) => {
62
+ const disabledAllCheckbox =
63
+ selectedRole === 'member' && action !== 'view'
64
+ return (
65
+ <ActionCheckbox
66
+ key={action}
67
+ label={action}
68
+ action={action}
69
+ isChecked={selectedActions.includes(action)}
70
+ isDisabled={disabledAllCheckbox}
71
+ onChange={handleActionChange}
72
+ />
73
+ )
74
+ })}
75
+ </Flex>
76
+ </Flex>
77
+ </Center>
78
+ <Stack spacing="base" py="base">
79
+ {rolePermissions.map(({ id, label, permissions }) => {
80
+ return (
81
+ <Flex key={id} w="100%">
82
+ <Flex flex="1">
83
+ <Text fontFamily="secondary" ml="base">
84
+ {label}
85
+ </Text>
86
+ </Flex>
87
+ <Flex flex="1" justify="space-evenly">
88
+ {actions.map((action) => {
89
+ const isDisabled =
90
+ !permissions[action].includes(selectedRole)
91
+ const isChecked =
92
+ callback[selectedRole][action].includes(id)
93
+ return (
94
+ <ActionCheckbox
95
+ key={action}
96
+ action={action}
97
+ isChecked={isChecked}
98
+ isDisabled={isDisabled}
99
+ onChange={() => handleFeatureChange(action, id)}
100
+ />
101
+ )
102
+ })}
103
+ </Flex>
104
+ </Flex>
105
+ )
106
+ })}
107
+ </Stack>
108
+ </Box>
109
+ </Flex>
110
+ )
111
+ }
@@ -0,0 +1,5 @@
1
+ export * from './ActionLabel'
2
+ export * from './ActionCheckbox'
3
+ export * from './PermissionsBanner'
4
+ export * from './RoleButton'
5
+ export * from './RolePermissionsTab'
@@ -1,4 +1,19 @@
1
- export const homeRoleTypes = ['member', 'contributor', 'manager', 'homeowner']
1
+ export type RoleType =
2
+ | 'guest'
3
+ | 'member'
4
+ | 'partner'
5
+ | 'contributor'
6
+ | 'manager'
7
+ | 'homeowner'
8
+
9
+ export type ReducedRoleType = 'member' | 'contributor' | 'manager'
10
+
11
+ export const homeRoleTypes: RoleType[] = [
12
+ 'member',
13
+ 'contributor',
14
+ 'manager',
15
+ 'homeowner',
16
+ ]
2
17
 
3
18
  export const homeRoles: { [key: string]: { [key: string]: string } } = {
4
19
  guest: {
@@ -0,0 +1,74 @@
1
+ import { RolePermissionI } from '@/interfaces'
2
+
3
+ export const rolePermissions: RolePermissionI[] = [
4
+ {
5
+ id: 'property-data',
6
+ label: 'Property Data',
7
+ permissions: {
8
+ view: ['member', 'contributor', 'manager'],
9
+ add: ['manager'],
10
+ edit: ['manager'],
11
+ delete: ['manager'],
12
+ },
13
+ },
14
+ {
15
+ id: 'financial-data',
16
+ label: 'Financial Data',
17
+ permissions: {
18
+ view: ['member', 'contributor', 'manager'],
19
+ add: ['contributor', 'manager'],
20
+ edit: ['manager'],
21
+ delete: ['manager'],
22
+ },
23
+ },
24
+ {
25
+ id: 'partners',
26
+ label: 'Partners',
27
+ permissions: {
28
+ view: ['member', 'contributor', 'manager'],
29
+ add: ['contributor', 'manager'],
30
+ edit: ['manager'],
31
+ delete: ['manager'],
32
+ },
33
+ },
34
+ {
35
+ id: 'folders',
36
+ label: 'Folders',
37
+ permissions: {
38
+ view: ['member', 'contributor', 'manager'],
39
+ add: ['manager'],
40
+ edit: ['contributor', 'manager'],
41
+ delete: ['manager'],
42
+ },
43
+ },
44
+ {
45
+ id: 'home-items',
46
+ label: 'Home items',
47
+ permissions: {
48
+ view: ['member', 'contributor', 'manager'],
49
+ add: ['contributor', 'manager'],
50
+ edit: ['manager'],
51
+ delete: ['manager'],
52
+ },
53
+ },
54
+ {
55
+ id: 'rooms',
56
+ label: 'Rooms',
57
+ permissions: {
58
+ view: ['member', 'contributor', 'manager'],
59
+ add: ['contributor', 'manager'],
60
+ edit: ['contributor', 'manager'],
61
+ delete: ['manager'],
62
+ },
63
+ },
64
+ {
65
+ id: 'rooms-items',
66
+ label: 'Rooms items',
67
+ permissions: {
68
+ view: ['member', 'contributor', 'manager'],
69
+ add: ['contributor', 'manager'],
70
+ edit: ['contributor', 'manager'],
71
+ delete: ['contributor', 'manager'],
72
+ },
73
+ },
74
+ ]
@@ -1,2 +1,3 @@
1
1
  export * from './CreditCardBrands.helper'
2
2
  export * from './PlanOptions.helper'
3
+ export * from './RolePermissions.helper'
@@ -3,4 +3,5 @@ export * from './usePaymentFormProvider'
3
3
  export * from './useMyProfileContent'
4
4
  export * from './usePaymentMethod'
5
5
  export * from './useProfileDetail'
6
- export * from './useTwoFactorSetting'
6
+ export * from './useRolePermissionsTab'
7
+ export * from './useTwoFactorSetting'
@@ -0,0 +1,104 @@
1
+ import { useState, useEffect } from 'react'
2
+ import { rolePermissions, ReducedRoleType } from '@/helpers'
3
+ import {
4
+ ActionsPermitted,
5
+ RolePermissionObject,
6
+ RolePermissionsTabI,
7
+ } from '@/interfaces'
8
+
9
+ export const useRolePermissionsTab = ({
10
+ selected,
11
+ onSelect,
12
+ }: RolePermissionsTabI) => {
13
+ const actions: ActionsPermitted[] = ['view', 'add', 'edit', 'delete']
14
+ const selectedActionsFromSelected = () => {
15
+ const selectedActions: ActionsPermitted[] = []
16
+ actions.forEach((action) => {
17
+ const featuresByRoleByAction = selected[selectedRole][action]
18
+ if (featuresByRoleByAction.length === rolePermissions.length) {
19
+ selectedActions.push(action)
20
+ }
21
+ })
22
+ return selectedActions
23
+ }
24
+ const [callback, setCallback] = useState<RolePermissionObject>(selected)
25
+ const [selectedRole, setSelectedRole] = useState<ReducedRoleType>('member')
26
+ const [selectedActions, setSelectedActions] = useState<ActionsPermitted[]>(
27
+ selectedActionsFromSelected
28
+ )
29
+
30
+ const handleRoleChange = (role: ReducedRoleType) => setSelectedRole(role)
31
+
32
+ const checkIfHasFeature = (action: ActionsPermitted, feature: string) => {
33
+ const features = callback[selectedRole][action]
34
+ const hasFeature = features.includes(feature)
35
+
36
+ if (hasFeature) {
37
+ return features.filter((f) => f !== feature)
38
+ }
39
+
40
+ return [...features, feature]
41
+ }
42
+
43
+ const handleFeatureChange = (action: ActionsPermitted, feature: string) => {
44
+ const newCallback = {
45
+ ...callback,
46
+ [selectedRole]: {
47
+ ...callback[selectedRole],
48
+ [action]: checkIfHasFeature(action, feature),
49
+ },
50
+ }
51
+ setCallback(newCallback)
52
+ onSelect(newCallback)
53
+ }
54
+
55
+ const handleActionChange = (action: ActionsPermitted) => {
56
+ if (selectedActions.includes(action)) {
57
+ const newCallback = {
58
+ ...callback,
59
+ [selectedRole]: {
60
+ ...callback[selectedRole],
61
+ [action]: [],
62
+ },
63
+ }
64
+ setCallback(newCallback)
65
+ onSelect(newCallback)
66
+ const filteredActions = selectedActions.filter((a) => a !== action)
67
+ return setSelectedActions(filteredActions)
68
+ }
69
+
70
+ const newCallback = {
71
+ ...callback,
72
+ [selectedRole]: {
73
+ ...callback[selectedRole],
74
+ [action]: rolePermissions
75
+ .map(({ id, permissions }) => {
76
+ if (permissions[action].includes(selectedRole)) {
77
+ return id
78
+ }
79
+
80
+ return ''
81
+ })
82
+ .filter((id) => id),
83
+ },
84
+ }
85
+
86
+ setCallback(newCallback)
87
+ onSelect(newCallback)
88
+
89
+ setSelectedActions([...selectedActions, action])
90
+ }
91
+
92
+ useEffect(() => {
93
+ setSelectedActions(selectedActionsFromSelected)
94
+ }, [selectedRole])
95
+ return {
96
+ actions,
97
+ callback,
98
+ selectedRole,
99
+ selectedActions,
100
+ handleRoleChange,
101
+ handleFeatureChange,
102
+ handleActionChange,
103
+ }
104
+ }
package/src/index.ts CHANGED
@@ -138,6 +138,7 @@ export {
138
138
  ResetPassword,
139
139
  ReviewBanner,
140
140
  RightPanel,
141
+ RolePermissionsTab,
141
142
  RoomHeader,
142
143
  RoomsBoardTour,
143
144
  RoomsMenu,
@@ -197,7 +198,7 @@ export {
197
198
  recordsInputsProxy,
198
199
  recordsInputsToDBProxy,
199
200
  userDetailsProxy,
200
- confirmAddressProxy
201
+ confirmAddressProxy,
201
202
  } from './proxies'
202
203
 
203
204
  import theme from './theme'
@@ -1,9 +1,10 @@
1
1
  import { ReactNode } from 'react'
2
2
 
3
3
  export interface MyProfileBodyI {
4
- account: ReactNode
5
- details: ReactNode
6
- email: ReactNode
4
+ account?: ReactNode
5
+ details?: ReactNode
6
+ email?: ReactNode
7
7
  isLoading: boolean
8
- payment: ReactNode
8
+ payment?: ReactNode
9
+ rolePermissions?: ReactNode
9
10
  }
@@ -1,6 +1,7 @@
1
1
  export * from './email'
2
2
  export * from './details'
3
3
  export * from './payment'
4
+ export * from './permissions'
4
5
  export * from './CancelAccount.interface'
5
6
  export * from './ContextButtons.interface'
6
7
  export * from './MyProfileBody.interface'
@@ -0,0 +1,9 @@
1
+ import { ActionsPermitted } from '@/interfaces'
2
+
3
+ export interface ActionCheckboxI {
4
+ action: ActionsPermitted
5
+ label?: string
6
+ isChecked: boolean
7
+ isDisabled: boolean
8
+ onChange: (action: ActionsPermitted) => void
9
+ }
@@ -0,0 +1,8 @@
1
+ import { RoleType } from '@/helpers'
2
+
3
+ export interface RoleButtonI {
4
+ role: RoleType
5
+ onClick: () => void
6
+ isSelected: boolean
7
+ showBorder?: boolean
8
+ }