Skip to content

Commit

Permalink
Feat/add user design (#981)
Browse files Browse the repository at this point in the history
* feat: add user to organization new flow

* feat: assign user roles

* update: made some db query change

* update: moved all styles in add user model to a new style file

* update: moved assign user role styles to style file

* update: updated syntax based on review

* feat: added search to find add user modal

* feat: added test for formatting roles that are displayed

* fix: fix import

* fix: moved function to another file

* update: added img for users without image
  • Loading branch information
tobi-bams authored Nov 24, 2023
1 parent 4cc379c commit e47bf76
Show file tree
Hide file tree
Showing 10 changed files with 656 additions and 155 deletions.
2 changes: 1 addition & 1 deletion db/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -1046,7 +1046,7 @@ func (db database) CreateOrEditOrganization(m Organization) (Organization, error
func (db database) GetOrganizationUsers(uuid string) ([]OrganizationUsersData, error) {
ms := []OrganizationUsersData{}

err := db.db.Raw(`SELECT org.org_uuid, org.created as user_created, person.* FROM public.organization_users AS org LEFT OUTER JOIN public.people AS person ON org.owner_pub_key = person.owner_pub_key WHERE org.org_uuid = '` + uuid + `' OR org.organization = '` + uuid + `' ORDER BY org.created DESC`).Find(&ms).Error
err := db.db.Raw(`SELECT org.org_uuid, org.created as user_created, person.* FROM public.organization_users AS org LEFT OUTER JOIN public.people AS person ON org.owner_pub_key = person.owner_pub_key WHERE org.org_uuid = '` + uuid + `' ORDER BY org.created DESC`).Find(&ms).Error

return ms, err
}
Expand Down
57 changes: 54 additions & 3 deletions frontend/app/src/helpers/__test__/helpers.spec.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import crypto from 'crypto';
import moment from 'moment';
import {
extractGithubIssueFromUrl,
extractRepoAndIssueFromIssueUrl,
Expand All @@ -6,10 +8,10 @@ import {
toCapitalize,
userHasRole,
spliceOutPubkey,
userHasManageBountyRoles
userHasManageBountyRoles,
RolesCategory,
handleDisplayRole
} from '../helpers-extended';
import crypto from 'crypto';
import moment from 'moment';

beforeAll(() => {
// for test randomString
Expand Down Expand Up @@ -210,4 +212,53 @@ describe('testing helpers', () => {
expect(pub).toBe(pubkey);
});
});

describe('format roles', () => {
test('should correctly set the default data roles for the first assigned user', () => {
const displayedRoles: RolesCategory[] = [];
const result = handleDisplayRole(displayedRoles);
expect(result.newDisplayedRoles).toEqual([]);
expect(result.tempDataRole).toEqual({});
});

test('should correctly update the status of a role if it is present in the default roles', () => {
const displayedRoles: RolesCategory[] = [
{ name: 'Manage bounties', roles: [], status: false },
{ name: 'Fund organization', roles: [], status: false },
{ name: 'Withdraw from organization', roles: [], status: false },
{ name: 'View transaction history', roles: [], status: false }
];
const result = handleDisplayRole(displayedRoles);
expect(result.newDisplayedRoles).toEqual([
{ name: 'Manage bounties', roles: [], status: true },
{ name: 'Fund organization', roles: [], status: true },
{ name: 'Withdraw from organization', roles: [], status: true },
{ name: 'View transaction history', roles: [], status: true }
]);
expect(result.tempDataRole).toEqual({});
});

test('should correctly update the tempDataRole object with the data roles of a role if it is present in the default roles', () => {
const displayedRoles: RolesCategory[] = [
{ name: 'Manage bounties', roles: ['role1', 'role2'], status: false },
{ name: 'Fund organization', roles: ['role3'], status: false },
{ name: 'Withdraw from organization', roles: ['role4'], status: false },
{ name: 'View transaction history', roles: ['role5'], status: false }
];
const result = handleDisplayRole(displayedRoles);
expect(result.newDisplayedRoles).toEqual([
{ name: 'Manage bounties', roles: ['role1', 'role2'], status: true },
{ name: 'Fund organization', roles: ['role3'], status: true },
{ name: 'Withdraw from organization', roles: ['role4'], status: true },
{ name: 'View transaction history', roles: ['role5'], status: true }
]);
expect(result.tempDataRole).toEqual({
role1: true,
role2: true,
role3: true,
role4: true,
role5: true
});
});
});
});
60 changes: 60 additions & 0 deletions frontend/app/src/helpers/helpers-extended.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,45 @@ export type Roles =

export const ManageBountiesGroup = ['ADD BOUNTY', 'UPDATE BOUNTY', 'DELETE BOUNTY', 'PAY BOUNTY'];

export interface RolesCategory {
name: string;
roles: string[];
status: boolean;
}

export const s_RolesCategories = [
{
name: 'Manage organization',
roles: ['EDIT ORGANIZATION'],
status: false
},
{
name: 'Manage bounties',
roles: ManageBountiesGroup,
status: false
},
{
name: 'Fund organization',
roles: ['ADD BUDGET'],
status: false
},
{
name: 'Withdraw from organization',
roles: ['WITHDRAW BUDGET'],
status: false
},
{
name: 'View transaction history',
roles: ['VIEW REPORT'],
status: false
},
{
name: 'Update members',
roles: ['ADD USER', 'UPDATE USER', 'DELETE USER', 'ADD ROLES'],
status: false
}
];

export const userHasRole = (
bountyRoles: any[],
userRoles: any[],
Expand Down Expand Up @@ -239,3 +278,24 @@ export const spliceOutPubkey = (userAddress: string): string => {

return userAddress;
};

export function handleDisplayRole(displayedRoles: RolesCategory[]) {
// Set default data roles for first assign user
const defaultRole = {
'Manage bounties': true,
'Fund organization': true,
'Withdraw from organization': true,
'View transaction history': true
};

const tempDataRole: { [id: string]: boolean } = {};
const newDisplayedRoles = displayedRoles.map((role: RolesCategory) => {
if (defaultRole[role.name]) {
role.status = true;
role.roles.forEach((dataRole: string) => (tempDataRole[dataRole] = true));
}
return role;
});

return { newDisplayedRoles, tempDataRole };
}
50 changes: 25 additions & 25 deletions frontend/app/src/people/widgetViews/AboutView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,33 +8,33 @@ import QrBar from '../utils/QrBar';
import { renderMarkdown } from '../utils/RenderMarkdown';

const Badge = styled.div`
display:flex;
justify-content:center;
align-items:center;
margin-left:10px;
height:20px;
color:#ffffff;
background: #1DA1F2;
border-radius: 32px;
font-weight: bold;
font-size: 8px;
line-height: 9px;
padding 0 10px;
display: flex;
justify-content: center;
align-items: center;
margin-left: 10px;
height: 20px;
color: #ffffff;
background: #1da1f2;
border-radius: 32px;
font-weight: bold;
font-size: 8px;
line-height: 9px;
padding: 0 10px;
`;
const CodeBadge = styled.div`
display:flex;
justify-content:center;
align-items:center;
margin-right:10px;
height:26px;
color:#5078F2;
background: #DCEDFE;
border-radius: 32px;
font-weight: bold;
font-size: 12px;
line-height: 13px;
padding 0 10px;
margin-bottom:10px;
display: flex;
justify-content: center;
align-items: center;
margin-right: 10px;
height: 26px;
color: #5078f2;
background: #dcedfe;
border-radius: 32px;
font-weight: bold;
font-size: 12px;
line-height: 13px;
padding: 0 10px;
margin-bottom: 10px;
`;
const ItemRow = styled.div`
display: flex;
Expand Down
28 changes: 26 additions & 2 deletions frontend/app/src/people/widgetViews/OrganizationDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import {
ViewBudgetWrap,
ViewBudgetTextWrap
} from './organization/style';
import AssignUserRoles from './organization/AssignUserRole';

let interval;

Expand Down Expand Up @@ -68,6 +69,7 @@ const OrganizationDetails = (props: {
const [toasts, setToasts]: any = useState([]);
const [invoiceStatus, setInvoiceStatus] = useState(false);
const { path, url } = useRouteMatch();
const [isOpenAssignRoles, setIsOpenAssignRoles] = useState<boolean>(false);

const isOrganizationAdmin = props.org?.owner_pubkey === ui.meInfo?.owner_pubkey;

Expand All @@ -86,7 +88,7 @@ const OrganizationDetails = (props: {
function addToast(title: string, color: 'danger' | 'success') {
setToasts([
{
id: '1',
id: `${Math.random()}`,
title,
color
}
Expand All @@ -101,6 +103,7 @@ const OrganizationDetails = (props: {
if (uuid) {
const users = await main.getOrganizationUsers(uuid);
setUsers(users);
return users;
}
}, [main, uuid]);

Expand Down Expand Up @@ -193,14 +196,24 @@ const OrganizationDetails = (props: {
setIsOpenWithdrawBudget(false);
};

const closeAssignRolesHandler = () => {
setIsOpenAssignRoles(false);
};

const onSubmitUser = async (body: any) => {
setIsLoading(true);

body.org_uuid = uuid;

const res = await main.addOrganizationUser(body);
if (res.status === 200) {
await getOrganizationUsers();
addToast('User added to organization successfully', 'success');
const recentUsers = await getOrganizationUsers();
const user = recentUsers?.filter((user: Person) => user.owner_pubkey === body.owner_pubkey);
if (user?.length === 1) {
setUser(user[0]);
setIsOpenAssignRoles(true);
}
} else {
addToast('Error: could not add user', 'danger');
}
Expand Down Expand Up @@ -452,6 +465,17 @@ const OrganizationDetails = (props: {
loading={loading}
/>
)}
{isOpenAssignRoles && (
<AssignUserRoles
close={closeAssignRolesHandler}
isOpen={isOpenAssignRoles}
loading={loading}
onSubmit={submitRoles}
user={user}
setLoading={setIsLoading}
addToast={addToast}
/>
)}
{isOpenRoles && (
<RolesModal
uuid={uuid}
Expand Down
Loading

0 comments on commit e47bf76

Please sign in to comment.