-
Notifications
You must be signed in to change notification settings - Fork 2.9k
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
[OldDot Rules Migration] Category Rules #48171
Changes from all commits
d11310f
ded08af
02d6924
547ecdd
afed691
d74d1ed
b9cbddb
7b5f5c3
d0e5dbb
daab3ea
04263e9
8823278
fff4963
06e7480
b8579b1
c80c57a
40c7959
8e6aaae
f86433e
f13b4ba
47eef1a
23ccd4d
444dee1
f7a497e
2e29d7f
725f7f4
703e105
b0834d3
b6f62d0
82dc463
7086acb
dbffc75
6d6e9d5
1145150
3abcbdb
c592466
b5ac473
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -786,6 +786,26 @@ const ROUTES = { | |
route: 'settings/workspaces/:policyID/categories/:categoryName/gl-code', | ||
getRoute: (policyID: string, categoryName: string) => `settings/workspaces/${policyID}/categories/${encodeURIComponent(categoryName)}/gl-code` as const, | ||
}, | ||
WORSKPACE_CATEGORY_DEFAULT_TAX_RATE: { | ||
route: 'settings/workspaces/:policyID/categories/:categoryName/tax-rate', | ||
getRoute: (policyID: string, categoryName: string) => `settings/workspaces/${policyID}/categories/${encodeURIComponent(categoryName)}/tax-rate` as const, | ||
}, | ||
WORSKPACE_CATEGORY_FLAG_AMOUNTS_OVER: { | ||
route: 'settings/workspaces/:policyID/categories/:categoryName/flag-amounts', | ||
getRoute: (policyID: string, categoryName: string) => `settings/workspaces/${policyID}/categories/${encodeURIComponent(categoryName)}/flag-amounts` as const, | ||
}, | ||
WORSKPACE_CATEGORY_DESCRIPTION_HINT: { | ||
route: 'settings/workspaces/:policyID/categories/:categoryName/description-hint', | ||
getRoute: (policyID: string, categoryName: string) => `settings/workspaces/${policyID}/categories/${encodeURIComponent(categoryName)}/description-hint` as const, | ||
}, | ||
WORSKPACE_CATEGORY_REQUIRE_RECEIPTS_OVER: { | ||
route: 'settings/workspaces/:policyID/categories/:categoryName/require-receipts-over', | ||
getRoute: (policyID: string, categoryName: string) => `settings/workspaces/${policyID}/categories/${encodeURIComponent(categoryName)}/require-receipts-over` as const, | ||
}, | ||
WORSKPACE_CATEGORY_APPROVER: { | ||
route: 'settings/workspaces/:policyID/categories/:categoryName/approver', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i think that the same table is missing the /workspaces/ in the category rules urls There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @WojtekBoman Did you resolve this comment? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, I've updated the category urls in the doc :) |
||
getRoute: (policyID: string, categoryName: string) => `settings/workspaces/${policyID}/categories/${encodeURIComponent(categoryName)}/approver` as const, | ||
}, | ||
WORKSPACE_MORE_FEATURES: { | ||
route: 'settings/workspaces/:policyID/more-features', | ||
getRoute: (policyID: string) => `settings/workspaces/${policyID}/more-features` as const, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -436,6 +436,11 @@ const SCREENS = { | |
CATEGORY_PAYROLL_CODE: 'Category_Payroll_Code', | ||
CATEGORY_GL_CODE: 'Category_GL_Code', | ||
CATEGORY_SETTINGS: 'Category_Settings', | ||
CATEGORY_DEFAULT_TAX_RATE: 'Category_Default_Tax_Rate', | ||
CATEGORY_FLAG_AMOUNTS_OVER: 'Category_Flag_Amounts_Over', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. as above |
||
CATEGORY_DESCRIPTION_HINT: 'Category_Description_Hint', | ||
CATEGORY_APPROVER: 'Category_Approver', | ||
CATEGORY_REQUIRE_RECEIPTS_OVER: 'Category_Require_Receipts_Over', | ||
CATEGORIES_SETTINGS: 'Categories_Settings', | ||
CATEGORIES_IMPORT: 'Categories_Import', | ||
CATEGORIES_IMPORTED: 'Categories_Imported', | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
import React, {useMemo} from 'react'; | ||
import type {SectionListData} from 'react-native'; | ||
import useDebouncedState from '@hooks/useDebouncedState'; | ||
import useLocalize from '@hooks/useLocalize'; | ||
import usePolicy from '@hooks/usePolicy'; | ||
import useScreenWrapperTranstionStatus from '@hooks/useScreenWrapperTransitionStatus'; | ||
import * as DeviceCapabilities from '@libs/DeviceCapabilities'; | ||
import * as OptionsListUtils from '@libs/OptionsListUtils'; | ||
import * as PolicyUtils from '@libs/PolicyUtils'; | ||
import CONST from '@src/CONST'; | ||
import type {Icon} from '@src/types/onyx/OnyxCommon'; | ||
import Badge from './Badge'; | ||
import {FallbackAvatar} from './Icon/Expensicons'; | ||
import {usePersonalDetails} from './OnyxProvider'; | ||
import SelectionList from './SelectionList'; | ||
import InviteMemberListItem from './SelectionList/InviteMemberListItem'; | ||
import type {Section} from './SelectionList/types'; | ||
|
||
type SelectionListApprover = { | ||
text: string; | ||
alternateText: string; | ||
keyForList: string; | ||
isSelected: boolean; | ||
login: string; | ||
rightElement?: React.ReactNode; | ||
icons: Icon[]; | ||
}; | ||
type ApproverSection = SectionListData<SelectionListApprover, Section<SelectionListApprover>>; | ||
|
||
type WorkspaceMembersSelectionListProps = { | ||
policyID: string; | ||
selectedApprover: string; | ||
setApprover: (email: string) => void; | ||
}; | ||
|
||
function WorkspaceMembersSelectionList({policyID, selectedApprover, setApprover}: WorkspaceMembersSelectionListProps) { | ||
const {translate} = useLocalize(); | ||
const {didScreenTransitionEnd} = useScreenWrapperTranstionStatus(); | ||
const [searchTerm, debouncedSearchTerm, setSearchTerm] = useDebouncedState(''); | ||
const personalDetails = usePersonalDetails(); | ||
const policy = usePolicy(policyID); | ||
|
||
const sections: ApproverSection[] = useMemo(() => { | ||
const approvers: SelectionListApprover[] = []; | ||
|
||
if (policy?.employeeList) { | ||
const availableApprovers = Object.values(policy.employeeList) | ||
.map((employee): SelectionListApprover | null => { | ||
const isAdmin = employee?.role === CONST.REPORT.ROLE.ADMIN; | ||
const email = employee.email; | ||
|
||
if (!email) { | ||
return null; | ||
} | ||
|
||
const policyMemberEmailsToAccountIDs = PolicyUtils.getMemberAccountIDsForWorkspace(policy?.employeeList); | ||
const accountID = Number(policyMemberEmailsToAccountIDs[email] ?? ''); | ||
const {avatar, displayName = email} = personalDetails?.[accountID] ?? {}; | ||
|
||
return { | ||
text: displayName, | ||
alternateText: email, | ||
keyForList: email, | ||
isSelected: selectedApprover === email, | ||
login: email, | ||
icons: [{source: avatar ?? FallbackAvatar, type: CONST.ICON_TYPE_AVATAR, name: displayName, id: accountID}], | ||
rightElement: isAdmin ? <Badge text={translate('common.admin')} /> : undefined, | ||
}; | ||
}) | ||
.filter((approver): approver is SelectionListApprover => !!approver); | ||
|
||
approvers.push(...availableApprovers); | ||
} | ||
|
||
const filteredApprovers = | ||
debouncedSearchTerm !== '' | ||
? approvers.filter((option) => { | ||
const searchValue = OptionsListUtils.getSearchValueForPhoneOrEmail(debouncedSearchTerm); | ||
const isPartOfSearchTerm = !!option.text?.toLowerCase().includes(searchValue) || !!option.login?.toLowerCase().includes(searchValue); | ||
return isPartOfSearchTerm; | ||
}) | ||
: approvers; | ||
|
||
return [ | ||
{ | ||
title: undefined, | ||
data: OptionsListUtils.sortAlphabetically(filteredApprovers, 'text'), | ||
shouldShow: true, | ||
}, | ||
]; | ||
}, [debouncedSearchTerm, personalDetails, policy?.employeeList, selectedApprover, translate]); | ||
|
||
const handleOnSelectRow = (approver: SelectionListApprover) => { | ||
setApprover(approver.login); | ||
}; | ||
|
||
const headerMessage = useMemo(() => (searchTerm && !sections[0].data.length ? translate('common.noResultsFound') : ''), [searchTerm, sections, translate]); | ||
|
||
return ( | ||
<SelectionList | ||
sections={sections} | ||
ListItem={InviteMemberListItem} | ||
textInputLabel={translate('selectionList.nameEmailOrPhoneNumber')} | ||
textInputValue={searchTerm} | ||
onChangeText={setSearchTerm} | ||
headerMessage={headerMessage} | ||
onSelectRow={handleOnSelectRow} | ||
showScrollIndicator | ||
showLoadingPlaceholder={!didScreenTransitionEnd} | ||
shouldPreventDefaultFocusOnSelectRow={!DeviceCapabilities.canUseTouchScreen()} | ||
/> | ||
); | ||
} | ||
|
||
export default WorkspaceMembersSelectionList; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
type RemovePolicyCategoryReceiptsRequiredParams = { | ||
policyID: string; | ||
categoryName: string; | ||
}; | ||
|
||
export default RemovePolicyCategoryReceiptsRequiredParams; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
type SetPolicyCategoryApproverParams = { | ||
policyID: string; | ||
categoryName: string; | ||
approver: string; | ||
}; | ||
|
||
export default SetPolicyCategoryApproverParams; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
type SetPolicyCategoryDescriptionRequiredParams = { | ||
policyID: string; | ||
categoryName: string; | ||
areCommentsRequired: boolean; | ||
}; | ||
|
||
export default SetPolicyCategoryDescriptionRequiredParams; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import type {PolicyCategoryExpenseLimitType} from '@src/types/onyx/PolicyCategory'; | ||
|
||
type SetPolicyCategoryMaxAmountParams = { | ||
policyID: string; | ||
categoryName: string; | ||
maxExpenseAmount: number | null; | ||
expenseLimitType: PolicyCategoryExpenseLimitType; | ||
}; | ||
|
||
export default SetPolicyCategoryMaxAmountParams; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
type SetPolicyCategoryReceiptsRequiredParams = { | ||
policyID: string; | ||
categoryName: string; | ||
maxExpenseAmountNoReceipt: number; | ||
}; | ||
|
||
export default SetPolicyCategoryReceiptsRequiredParams; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
type SetPolicyCategoryTaxParams = { | ||
policyID: string; | ||
categoryName: string; | ||
taxID: string; | ||
}; | ||
|
||
export default SetPolicyCategoryTaxParams; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
type SetWorkspaceCategoryDescriptionHintParams = { | ||
policyID: string; | ||
categoryName: string; | ||
commentHint: string; | ||
}; | ||
|
||
export default SetWorkspaceCategoryDescriptionHintParams; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shouldn't it be
flag-amount
as in the design doc table?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is correct, I named it wrong in the design doc, I thought the site was called
Flag Amount over
. I'll adjust the table in the doc