@mx-cartographer/experiences 9.3.1 → 9.3.3
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.
- package/CHANGELOG.md +9 -0
- package/dist/core/api/SettingsApi.d.ts +4 -0
- package/dist/core/api/SettingsApi.es.js +5 -4
- package/dist/core/api/SettingsApi.es.js.map +1 -1
- package/dist/core/constants/ApiEndpoints.d.ts +1 -0
- package/dist/core/constants/ApiEndpoints.es.js +1 -0
- package/dist/core/constants/ApiEndpoints.es.js.map +1 -1
- package/dist/core/stores/SettingsStore.d.ts +4 -0
- package/dist/core/stores/SettingsStore.es.js +80 -73
- package/dist/core/stores/SettingsStore.es.js.map +1 -1
- package/dist/core/types/localization/SettingsCopy.d.ts +6 -0
- package/dist/core/utils/TransactionUtils.es.js +31 -30
- package/dist/core/utils/TransactionUtils.es.js.map +1 -1
- package/dist/dashboard/Greeting.es.js +18 -19
- package/dist/dashboard/Greeting.es.js.map +1 -1
- package/dist/settings/components/profile/ProfileTab.d.ts +1 -1
- package/dist/settings/components/profile/ProfileTab.es.js +115 -108
- package/dist/settings/components/profile/ProfileTab.es.js.map +1 -1
- package/dist/settings/components/profile/actions/ResetPasswordAction.d.ts +4 -0
- package/dist/settings/components/profile/actions/ResetPasswordAction.es.js +94 -0
- package/dist/settings/components/profile/actions/ResetPasswordAction.es.js.map +1 -0
- package/dist/settings/components/profile/actions/VerifyEmailAction.es.js +20 -37
- package/dist/settings/components/profile/actions/VerifyEmailAction.es.js.map +1 -1
- package/dist/settings/components/profile/actions/VerifyPhoneAction.es.js +11 -17
- package/dist/settings/components/profile/actions/VerifyPhoneAction.es.js.map +1 -1
- package/dist/settings/constants/Settings.d.ts +8 -0
- package/dist/settings/constants/Settings.es.js +10 -3
- package/dist/settings/constants/Settings.es.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TransactionUtils.es.js","names":[],"sources":["../../../src/core/utils/TransactionUtils.ts"],"sourcesContent":["import { endOfToday } from 'date-fns/endOfToday'\nimport { format } from 'date-fns/format'\nimport { fromUnixTime } from 'date-fns/fromUnixTime'\nimport { getUnixTime } from 'date-fns/getUnixTime'\nimport { startOfMonth } from 'date-fns/startOfMonth'\nimport { startOfToday } from 'date-fns/startOfToday'\n\nimport { TABLE_CONST } from '../constants/Table'\nimport {\n CategoryGuids,\n CategoryGuidToName,\n DATE_FORMATS_INTL,\n formatDate,\n ORDINAL_DATE_FORMAT,\n} from '../constants'\nimport { COLUMN_NAMES } from '../constants/Transaction'\nimport { TransactionStatus, TransactionType } from '../types'\nimport type { Account, Category, Tag, Tagging, Transaction } from '../types'\n\nimport { type TransactionFilter } from '../stores/TransactionStore'\n\nimport { formatCurrency } from './NumberFormatting'\n\ninterface AccountsMap {\n [key: string]: Account\n}\n\ninterface CategoriesMap {\n [key: string]: Category\n}\n\ninterface TaggingsMap {\n [key: string]: string[]\n}\n\nexport const buildDetailedTransactions = (\n transactions: Transaction[],\n accounts: Account[],\n categories: Category[],\n taggings: Tagging[] = [],\n) => {\n const accountsMap = accounts.reduce((acc: AccountsMap, account: Account) => {\n return { ...acc, [account.guid]: account }\n }, {})\n\n const categoriesMap = categories.reduce((acc: CategoriesMap, category: Category) => {\n return { ...acc, [category.guid]: category }\n }, {})\n\n const taggingsMap = taggings.reduce((acc: TaggingsMap, tagging: Tagging) => {\n const { transaction_guid, tag_guid } = tagging\n\n if (!acc[transaction_guid]) {\n return {\n ...acc,\n [transaction_guid]: [tag_guid],\n }\n }\n const tags = [...acc[transaction_guid], tag_guid] as string[]\n\n return {\n ...acc,\n [transaction_guid]: tags,\n }\n }, {})\n\n return transactions.map((transaction: Transaction) => {\n const account = accountsMap[transaction.account_guid]\n const category = transaction.category_guid ? categoriesMap[transaction.category_guid] : null\n const tags = taggingsMap[transaction.guid] ?? []\n\n return {\n ...transaction,\n account: account?.user_name || 'Unknown',\n accountIsClosed: account?.is_closed,\n accountIsHidden: account?.is_hidden,\n category: category?.name || 'Uncategorized',\n isIncome: transaction.top_level_category_guid === CategoryGuids.INCOME,\n isPending: transaction.feed_status === TransactionStatus.PENDING,\n number: account?.account_number || '',\n payee: transaction.description,\n tags,\n }\n })\n}\n\nconst UNCATEGORIZED_TERM = 'uncategorized'\n\nexport const sortAndFilterTransactions = (\n filter: TransactionFilter,\n expandedSplits: string[],\n sortColumn: string,\n sortDirection: string,\n tags: Tag[],\n transactions: Transaction[],\n) => {\n const filteredTransactions = filterTransactions(filter, tags, transactions)\n\n const sortedTransactions = sortTransactions(filteredTransactions, sortColumn, sortDirection)\n\n expandedSplits.forEach((guid) => {\n const index = sortedTransactions.findIndex((t) => t.guid === guid)\n const children = transactions.filter((t) => t.parent_guid === guid)\n sortedTransactions.splice(index + 1, 0, ...children)\n })\n return sortedTransactions\n}\n\nconst filterTransactions = (\n filter: TransactionFilter,\n tags: Tag[],\n transactions: Transaction[],\n) => {\n const {\n accounts = [],\n dateRange = { start: startOfMonth(startOfToday()), end: endOfToday() },\n custom = () => true,\n searchTerm: searchFilter = '',\n showSplits = false,\n } = filter\n\n return (\n transactions\n // Filters out parent of split transactions when showSplits is true and filters out split\n // transaction children when showSplits is false\n .filter((t) => (showSplits ? !t.has_been_split : !t.parent_guid))\n // Filter for selected accounts\n .filter((t) => Boolean(accounts.find((guid) => guid === t.account_guid)))\n // Filter for Date Range\n .filter((t) => t.date >= getUnixTime(dateRange.start) && t.date <= getUnixTime(dateRange.end))\n // Custom filter\n .filter(custom)\n // Search filter\n .filter((transaction) => {\n // Don't return uncategorized split transactions\n if (searchFilter === UNCATEGORIZED_TERM && transaction.has_been_split) {\n return false\n }\n\n // Split check - When searching for \"Splits\" and transaction is a split or is a parent of a split(s)\n const splitPattern = /^spl/i\n if (\n splitPattern.test(searchFilter) &&\n (transaction.has_been_split || Boolean(transaction.parent_guid))\n ) {\n return true\n }\n\n // Check transactions tags\n const isTagIncludedInSearch = transaction.tags.some((guid) =>\n isIncludedInSearch(searchFilter, tags.find((tag) => tag.guid === guid)?.name),\n )\n const date = fromUnixTime(transaction.date)\n return (\n isIncludedInSearch(searchFilter, transaction.payee) ||\n isIncludedInSearch(searchFilter, transaction.feed_description) ||\n isIncludedInSearch(searchFilter, transaction.category) ||\n isIncludedInSearch(searchFilter, formatDate(date, DATE_FORMATS_INTL.MONTH)) ||\n isIncludedInSearch(searchFilter, formatDate(date, DATE_FORMATS_INTL.DAY)) ||\n isIncludedInSearch(searchFilter, formatDate(date, DATE_FORMATS_INTL.FULL_MONTH_DAY)) ||\n isIncludedInSearch(searchFilter, formatDate(date, DATE_FORMATS_INTL.MONTH_DAY_YEAR)) ||\n isIncludedInSearch(searchFilter, format(date, ORDINAL_DATE_FORMAT)) ||\n isIncludedInSearch(searchFilter, transaction.account) ||\n isIncludedInSearch(searchFilter, formatCurrency(transaction.amount, '0,0.00')) ||\n isIncludedInSearch(searchFilter, transaction.memo) ||\n isTagIncludedInSearch\n )\n })\n )\n}\n\nconst sortTransactions = (\n transactions: Transaction[],\n sortColumn: string,\n sortDirection: string,\n) => {\n return [...transactions].sort((a: Transaction, b: Transaction) => {\n const column = sortColumn as keyof Transaction\n const sortCompare = (a[column] || '') > (b[column] || '')\n\n let sortASC = sortCompare ? -1 : 1\n let sortDESC = sortCompare ? 1 : -1\n\n if (sortColumn === COLUMN_NAMES.DATE || sortColumn === COLUMN_NAMES.AMOUNT) {\n sortASC = sortCompare ? 1 : -1\n sortDESC = sortCompare ? -1 : 1\n }\n\n return sortDirection === TABLE_CONST.ASC ? sortASC : sortDESC\n })\n}\n\n/**\n * Determines if a value is included within the terms set in the search bar\n */\nconst isIncludedInSearch = (searchFilter: string, value: string | null | undefined) => {\n const lowerCasedTerms = searchFilter.toLowerCase().split(' ')\n const lowerCasedValue = value?.toString().toLowerCase() ?? ''\n\n return lowerCasedTerms.every((filter) => lowerCasedValue.indexOf(filter) > -1)\n}\n\n// TODO: Change the way formatting data is exported in order to handle localization\ntype FormattedTransaction = {\n Date: string\n Description: string\n 'Original Description': string\n Amount: string\n Type: string\n 'Parent Category': string\n Category: string\n Account: string\n Tags: string\n Memo: string\n Pending: string\n}\n\n/**\n * Collects the GUIDs of all transactions that act as parents\n * to one or more split (child) transactions.\n */\nfunction extractParentTransactionGuids(transactions: Transaction[]): Set<string> {\n return new Set(\n transactions.filter((tx) => tx.parent_guid !== undefined).map((tx) => tx.parent_guid!),\n )\n}\n\n/**\n * Organizes child transactions by their parent transaction GUID.\n * Returns a map from parent GUID to an array of its child transactions.\n */\nfunction mapChildTransactionsByParent(transactions: Transaction[]): Record<string, Transaction[]> {\n return transactions.reduce<Record<string, Transaction[]>>((accumulator, tx) => {\n if (tx.parent_guid) {\n if (!accumulator[tx.parent_guid]) accumulator[tx.parent_guid] = []\n accumulator[tx.parent_guid].push(tx)\n }\n return accumulator\n }, {})\n}\n\n/**\n * Produces a list of transactions based on the given sorted transactions,\n * where parent transactions that have split children are replaced by those\n * children sorted by descending absolute amount. All other transactions\n * are included as-is, with duplicates removed.\n */\nexport function flattenTransactionsWithSplits(\n sortedTransactions: Transaction[],\n allTransactions: Transaction[],\n): Transaction[] {\n // Set of parent transaction GUIDs that have split child transactions\n const parentTransactionGuidsWithSplits = extractParentTransactionGuids(allTransactions)\n\n // Map from parent GUID to array of its child split transactions\n const childTransactionsGroupedByParent = mapChildTransactionsByParent(allTransactions)\n\n // Track GUIDs of transactions already included in the result to avoid duplicates\n const processedTransactionGuids = new Set<string>()\n\n // Resulting list of transactions with parents replaced by their split children\n const flattenedTransactionList: Transaction[] = []\n\n for (const transaction of sortedTransactions) {\n if (parentTransactionGuidsWithSplits.has(transaction.guid)) {\n // This transaction is a parent with splits, so replace it with its children\n const splitChildTransactions = childTransactionsGroupedByParent[transaction.guid] ?? []\n\n splitChildTransactions\n .slice()\n .sort((a, b) => Math.abs(b.amount) - Math.abs(a.amount))\n .forEach((childTransaction) => {\n if (!processedTransactionGuids.has(childTransaction.guid)) {\n flattenedTransactionList.push(childTransaction)\n processedTransactionGuids.add(childTransaction.guid)\n }\n })\n } else if (!processedTransactionGuids.has(transaction.guid)) {\n // Normal transaction (no splits), add as-is if not already added\n flattenedTransactionList.push(transaction)\n processedTransactionGuids.add(transaction.guid)\n }\n }\n\n return flattenedTransactionList\n}\n\nexport const exportTransactionsToCSV = (transactions: Transaction[], tags: Tag[]) => {\n const csvContent = structureCSVData(formatTransactions(transactions, tags))\n\n const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' })\n const link = document.createElement('a')\n link.href = URL.createObjectURL(blob)\n link.setAttribute('download', 'transactions.csv')\n\n document.body.appendChild(link)\n link.click()\n document.body.removeChild(link)\n\n URL.revokeObjectURL(link.href)\n}\n\n/**\n * Formats a list of transactions into a list that will be used when\n * downloaded to a CSV file.\n */\nconst formatTransactions = (transactions: Transaction[], tags: Tag[]) => {\n return transactions.map((transaction) => ({\n Date: formatDate(fromUnixTime(transaction.date), DATE_FORMATS_INTL.YEAR_MONTH_DAY),\n Description: getDescription(transaction),\n 'Original Description': transaction.feed_description,\n Amount: `${transaction.amount}`,\n Type: transaction.transaction_type === TransactionType.CREDIT ? 'Credit' : 'Debit',\n 'Parent Category': CategoryGuidToName[transaction.top_level_category_guid || ''],\n Category: transaction.category,\n Account: transaction.account,\n Tags: getTags(transaction, tags),\n Memo: transaction.memo,\n Pending: transaction.isPending ? 'TRUE' : 'FALSE',\n })) as FormattedTransaction[]\n}\n\n/**\n * Escapes a value for safe CSV output\n */\nconst escapeCsvField = (field?: string | null): string => {\n if (!field) return ''\n return /[,\"\\n\\r]/.test(field) ? `\"${field.replace(/\"/g, '\"\"')}\"` : field\n}\n\n/**\n * Structures the CSV file data using the formatted transactions\n */\nconst structureCSVData = (formattedTransactions: FormattedTransaction[]) => {\n const csvHeader = Object.keys(formattedTransactions[0]).join(',').concat('\\r\\n')\n const csvRows = formattedTransactions\n .map((transaction) => Object.values(transaction).map(escapeCsvField).join(','))\n .join('\\r\\n')\n\n return csvHeader + csvRows\n}\n\n/**\n * Get the description for a transaction that will be used within the CSV copy.\n * We want to highlight that split transactions are a split as well as\n * hidden transactions are hidden.\n */\nconst getDescription = (transaction: Transaction) => {\n let description = transaction.parent_guid ? 'Split: ' : ''\n description += transaction.is_hidden ? '(Excluded) ' : ''\n description += transaction.description\n\n return description\n}\n\nconst getTags = (transaction: Transaction, tags: Tag[]) => {\n return transaction.tags\n .map((tagGuid) => {\n const tag = tags.filter((t) => t.guid === tagGuid)[0]\n\n return tag?.name ?? ''\n })\n .join(' ')\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TransactionUtils.es.js","names":[],"sources":["../../../src/core/utils/TransactionUtils.ts"],"sourcesContent":["import { endOfToday } from 'date-fns/endOfToday'\nimport { format } from 'date-fns/format'\nimport { fromUnixTime } from 'date-fns/fromUnixTime'\nimport { getUnixTime } from 'date-fns/getUnixTime'\nimport { startOfMonth } from 'date-fns/startOfMonth'\nimport { startOfToday } from 'date-fns/startOfToday'\n\nimport { TABLE_CONST } from '../constants/Table'\nimport {\n CategoryGuids,\n CategoryGuidToName,\n DATE_FORMATS_INTL,\n formatDate,\n ORDINAL_DATE_FORMAT,\n} from '../constants'\nimport { COLUMN_NAMES } from '../constants/Transaction'\nimport { TransactionStatus, TransactionType } from '../types'\nimport type { Account, Category, Tag, Tagging, Transaction } from '../types'\n\nimport { type TransactionFilter } from '../stores/TransactionStore'\n\nimport { fromUnixUTC } from './DateUtil'\nimport { formatCurrency } from './NumberFormatting'\n\ninterface AccountsMap {\n [key: string]: Account\n}\n\ninterface CategoriesMap {\n [key: string]: Category\n}\n\ninterface TaggingsMap {\n [key: string]: string[]\n}\n\nexport const buildDetailedTransactions = (\n transactions: Transaction[],\n accounts: Account[],\n categories: Category[],\n taggings: Tagging[] = [],\n) => {\n const accountsMap = accounts.reduce((acc: AccountsMap, account: Account) => {\n return { ...acc, [account.guid]: account }\n }, {})\n\n const categoriesMap = categories.reduce((acc: CategoriesMap, category: Category) => {\n return { ...acc, [category.guid]: category }\n }, {})\n\n const taggingsMap = taggings.reduce((acc: TaggingsMap, tagging: Tagging) => {\n const { transaction_guid, tag_guid } = tagging\n\n if (!acc[transaction_guid]) {\n return {\n ...acc,\n [transaction_guid]: [tag_guid],\n }\n }\n const tags = [...acc[transaction_guid], tag_guid] as string[]\n\n return {\n ...acc,\n [transaction_guid]: tags,\n }\n }, {})\n\n return transactions.map((transaction: Transaction) => {\n const account = accountsMap[transaction.account_guid]\n const category = transaction.category_guid ? categoriesMap[transaction.category_guid] : null\n const tags = taggingsMap[transaction.guid] ?? []\n\n return {\n ...transaction,\n account: account?.user_name || 'Unknown',\n accountIsClosed: account?.is_closed,\n accountIsHidden: account?.is_hidden,\n category: category?.name || 'Uncategorized',\n isIncome: transaction.top_level_category_guid === CategoryGuids.INCOME,\n isPending: transaction.feed_status === TransactionStatus.PENDING,\n number: account?.account_number || '',\n payee: transaction.description,\n tags,\n }\n })\n}\n\nconst UNCATEGORIZED_TERM = 'uncategorized'\n\nexport const sortAndFilterTransactions = (\n filter: TransactionFilter,\n expandedSplits: string[],\n sortColumn: string,\n sortDirection: string,\n tags: Tag[],\n transactions: Transaction[],\n) => {\n const filteredTransactions = filterTransactions(filter, tags, transactions)\n\n const sortedTransactions = sortTransactions(filteredTransactions, sortColumn, sortDirection)\n\n expandedSplits.forEach((guid) => {\n const index = sortedTransactions.findIndex((t) => t.guid === guid)\n const children = transactions.filter((t) => t.parent_guid === guid)\n sortedTransactions.splice(index + 1, 0, ...children)\n })\n return sortedTransactions\n}\n\nconst filterTransactions = (\n filter: TransactionFilter,\n tags: Tag[],\n transactions: Transaction[],\n) => {\n const {\n accounts = [],\n dateRange = { start: startOfMonth(startOfToday()), end: endOfToday() },\n custom = () => true,\n searchTerm: searchFilter = '',\n showSplits = false,\n } = filter\n\n return (\n transactions\n // Filters out parent of split transactions when showSplits is true and filters out split\n // transaction children when showSplits is false\n .filter((t) => (showSplits ? !t.has_been_split : !t.parent_guid))\n // Filter for selected accounts\n .filter((t) => Boolean(accounts.find((guid) => guid === t.account_guid)))\n // Filter for Date Range.\n // NOTE: bounds are local-midnight (getUnixTime of a local Date) while dates\n // are rendered/exported on the UTC calendar day (fromUnixUTC). For a\n // midnight-UTC row near a month boundary in a negative-offset browser the\n // two can disagree by a day. Left as-is here to keep this fix low-risk;\n // unifying range + search on UTC is tracked with the core-data ISO\n // migration (MEW-3961 follow-up).\n .filter((t) => t.date >= getUnixTime(dateRange.start) && t.date <= getUnixTime(dateRange.end))\n // Custom filter\n .filter(custom)\n // Search filter\n .filter((transaction) => {\n // Don't return uncategorized split transactions\n if (searchFilter === UNCATEGORIZED_TERM && transaction.has_been_split) {\n return false\n }\n\n // Split check - When searching for \"Splits\" and transaction is a split or is a parent of a split(s)\n const splitPattern = /^spl/i\n if (\n splitPattern.test(searchFilter) &&\n (transaction.has_been_split || Boolean(transaction.parent_guid))\n ) {\n return true\n }\n\n // Check transactions tags\n const isTagIncludedInSearch = transaction.tags.some((guid) =>\n isIncludedInSearch(searchFilter, tags.find((tag) => tag.guid === guid)?.name),\n )\n const date = fromUnixTime(transaction.date)\n return (\n isIncludedInSearch(searchFilter, transaction.payee) ||\n isIncludedInSearch(searchFilter, transaction.feed_description) ||\n isIncludedInSearch(searchFilter, transaction.category) ||\n isIncludedInSearch(searchFilter, formatDate(date, DATE_FORMATS_INTL.MONTH)) ||\n isIncludedInSearch(searchFilter, formatDate(date, DATE_FORMATS_INTL.DAY)) ||\n isIncludedInSearch(searchFilter, formatDate(date, DATE_FORMATS_INTL.FULL_MONTH_DAY)) ||\n isIncludedInSearch(searchFilter, formatDate(date, DATE_FORMATS_INTL.MONTH_DAY_YEAR)) ||\n isIncludedInSearch(searchFilter, format(date, ORDINAL_DATE_FORMAT)) ||\n isIncludedInSearch(searchFilter, transaction.account) ||\n isIncludedInSearch(searchFilter, formatCurrency(transaction.amount, '0,0.00')) ||\n isIncludedInSearch(searchFilter, transaction.memo) ||\n isTagIncludedInSearch\n )\n })\n )\n}\n\nconst sortTransactions = (\n transactions: Transaction[],\n sortColumn: string,\n sortDirection: string,\n) => {\n return [...transactions].sort((a: Transaction, b: Transaction) => {\n const column = sortColumn as keyof Transaction\n const sortCompare = (a[column] || '') > (b[column] || '')\n\n let sortASC = sortCompare ? -1 : 1\n let sortDESC = sortCompare ? 1 : -1\n\n if (sortColumn === COLUMN_NAMES.DATE || sortColumn === COLUMN_NAMES.AMOUNT) {\n sortASC = sortCompare ? 1 : -1\n sortDESC = sortCompare ? -1 : 1\n }\n\n return sortDirection === TABLE_CONST.ASC ? sortASC : sortDESC\n })\n}\n\n/**\n * Determines if a value is included within the terms set in the search bar\n */\nconst isIncludedInSearch = (searchFilter: string, value: string | null | undefined) => {\n const lowerCasedTerms = searchFilter.toLowerCase().split(' ')\n const lowerCasedValue = value?.toString().toLowerCase() ?? ''\n\n return lowerCasedTerms.every((filter) => lowerCasedValue.indexOf(filter) > -1)\n}\n\n// TODO: Change the way formatting data is exported in order to handle localization\ntype FormattedTransaction = {\n Date: string\n Description: string\n 'Original Description': string\n Amount: string\n Type: string\n 'Parent Category': string\n Category: string\n Account: string\n Tags: string\n Memo: string\n Pending: string\n}\n\n/**\n * Collects the GUIDs of all transactions that act as parents\n * to one or more split (child) transactions.\n */\nfunction extractParentTransactionGuids(transactions: Transaction[]): Set<string> {\n return new Set(\n transactions.filter((tx) => tx.parent_guid !== undefined).map((tx) => tx.parent_guid!),\n )\n}\n\n/**\n * Organizes child transactions by their parent transaction GUID.\n * Returns a map from parent GUID to an array of its child transactions.\n */\nfunction mapChildTransactionsByParent(transactions: Transaction[]): Record<string, Transaction[]> {\n return transactions.reduce<Record<string, Transaction[]>>((accumulator, tx) => {\n if (tx.parent_guid) {\n if (!accumulator[tx.parent_guid]) accumulator[tx.parent_guid] = []\n accumulator[tx.parent_guid].push(tx)\n }\n return accumulator\n }, {})\n}\n\n/**\n * Produces a list of transactions based on the given sorted transactions,\n * where parent transactions that have split children are replaced by those\n * children sorted by descending absolute amount. All other transactions\n * are included as-is, with duplicates removed.\n */\nexport function flattenTransactionsWithSplits(\n sortedTransactions: Transaction[],\n allTransactions: Transaction[],\n): Transaction[] {\n // Set of parent transaction GUIDs that have split child transactions\n const parentTransactionGuidsWithSplits = extractParentTransactionGuids(allTransactions)\n\n // Map from parent GUID to array of its child split transactions\n const childTransactionsGroupedByParent = mapChildTransactionsByParent(allTransactions)\n\n // Track GUIDs of transactions already included in the result to avoid duplicates\n const processedTransactionGuids = new Set<string>()\n\n // Resulting list of transactions with parents replaced by their split children\n const flattenedTransactionList: Transaction[] = []\n\n for (const transaction of sortedTransactions) {\n if (parentTransactionGuidsWithSplits.has(transaction.guid)) {\n // This transaction is a parent with splits, so replace it with its children\n const splitChildTransactions = childTransactionsGroupedByParent[transaction.guid] ?? []\n\n splitChildTransactions\n .slice()\n .sort((a, b) => Math.abs(b.amount) - Math.abs(a.amount))\n .forEach((childTransaction) => {\n if (!processedTransactionGuids.has(childTransaction.guid)) {\n flattenedTransactionList.push(childTransaction)\n processedTransactionGuids.add(childTransaction.guid)\n }\n })\n } else if (!processedTransactionGuids.has(transaction.guid)) {\n // Normal transaction (no splits), add as-is if not already added\n flattenedTransactionList.push(transaction)\n processedTransactionGuids.add(transaction.guid)\n }\n }\n\n return flattenedTransactionList\n}\n\nexport const exportTransactionsToCSV = (transactions: Transaction[], tags: Tag[]) => {\n const csvContent = structureCSVData(formatTransactions(transactions, tags))\n\n const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' })\n const link = document.createElement('a')\n link.href = URL.createObjectURL(blob)\n link.setAttribute('download', 'transactions.csv')\n\n document.body.appendChild(link)\n link.click()\n document.body.removeChild(link)\n\n URL.revokeObjectURL(link.href)\n}\n\n/**\n * Formats a list of transactions into a list that will be used when\n * downloaded to a CSV file.\n */\nconst formatTransactions = (transactions: Transaction[], tags: Tag[]) => {\n return transactions.map((transaction) => ({\n // Post dates are calendar days; format on the UTC day so the export can't\n // shift to the prior day in a Western-offset browser.\n Date: formatDate(fromUnixUTC(transaction.date), DATE_FORMATS_INTL.YEAR_MONTH_DAY),\n Description: getDescription(transaction),\n 'Original Description': transaction.feed_description,\n Amount: `${transaction.amount}`,\n Type: transaction.transaction_type === TransactionType.CREDIT ? 'Credit' : 'Debit',\n 'Parent Category': CategoryGuidToName[transaction.top_level_category_guid || ''],\n Category: transaction.category,\n Account: transaction.account,\n Tags: getTags(transaction, tags),\n Memo: transaction.memo,\n Pending: transaction.isPending ? 'TRUE' : 'FALSE',\n })) as FormattedTransaction[]\n}\n\n/**\n * Escapes a value for safe CSV output\n */\nconst escapeCsvField = (field?: string | null): string => {\n if (!field) return ''\n return /[,\"\\n\\r]/.test(field) ? `\"${field.replace(/\"/g, '\"\"')}\"` : field\n}\n\n/**\n * Structures the CSV file data using the formatted transactions\n */\nconst structureCSVData = (formattedTransactions: FormattedTransaction[]) => {\n // Guard the empty export: Object.keys(undefined) would throw for a zero-row\n // list (e.g. an over-filtered range), so emit an empty file instead.\n if (formattedTransactions.length === 0) return ''\n\n const csvHeader = Object.keys(formattedTransactions[0]).join(',').concat('\\r\\n')\n const csvRows = formattedTransactions\n .map((transaction) => Object.values(transaction).map(escapeCsvField).join(','))\n .join('\\r\\n')\n\n return csvHeader + csvRows\n}\n\n/**\n * Get the description for a transaction that will be used within the CSV copy.\n * We want to highlight that split transactions are a split as well as\n * hidden transactions are hidden.\n */\nconst getDescription = (transaction: Transaction) => {\n let description = transaction.parent_guid ? 'Split: ' : ''\n description += transaction.is_hidden ? '(Excluded) ' : ''\n description += transaction.description\n\n return description\n}\n\nconst getTags = (transaction: Transaction, tags: Tag[]) => {\n return transaction.tags\n .map((tagGuid) => {\n const tag = tags.filter((t) => t.guid === tagGuid)[0]\n\n return tag?.name ?? ''\n })\n .join(' ')\n}\n"],"mappings":"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"}
|
|
@@ -1,49 +1,48 @@
|
|
|
1
|
-
import { useAppConfig as
|
|
1
|
+
import { useAppConfig as d, useGlobalCopyStore as p } from "../common/context/hooks.es.js";
|
|
2
2
|
import { useScreenSize as g } from "../common/hooks/useScreenSize.es.js";
|
|
3
|
-
import { GlobalAccountFilter as
|
|
4
|
-
import
|
|
5
|
-
import
|
|
3
|
+
import { GlobalAccountFilter as u } from "../common/components/GlobalAccountFilter.es.js";
|
|
4
|
+
import h from "../common/components/ConnectDrawer.es.js";
|
|
5
|
+
import _ from "../common/components/addaccounts/AddAccounts.es.js";
|
|
6
6
|
import s from "react";
|
|
7
7
|
import { observer as C } from "mobx-react-lite";
|
|
8
8
|
import n from "@mui/material/Stack";
|
|
9
|
-
import { H2 as
|
|
10
|
-
import
|
|
9
|
+
import { H2 as w, P as v } from "@mxenabled/mxui";
|
|
10
|
+
import x from "@mui/material/Paper";
|
|
11
11
|
import { jsx as e, jsxs as r } from "react/jsx-runtime";
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const [i, c] = s.useState(!1), m = y("(max-width:320px)"), { common: o, connect: l } = u(), { config: a } = p(), { isMobile: f } = g(), d = () => {
|
|
12
|
+
var b = () => {
|
|
13
|
+
const [i, c] = s.useState(!1), { common: o, connect: m } = p(), { config: l } = d(), { isMobile: a } = g(), f = () => {
|
|
15
14
|
const t = (/* @__PURE__ */ new Date()).getHours();
|
|
16
15
|
return t > 1 && t < 12 ? o.good_morning : t >= 12 && t < 18 ? o.good_afternoon : o.good_evening;
|
|
17
16
|
};
|
|
18
|
-
return /* @__PURE__ */ r(s.Fragment, { children: [/* @__PURE__ */ e(
|
|
17
|
+
return /* @__PURE__ */ r(s.Fragment, { children: [/* @__PURE__ */ e(x, {
|
|
19
18
|
sx: {
|
|
20
19
|
gap: 12,
|
|
21
|
-
mb:
|
|
20
|
+
mb: a ? 24 : 0,
|
|
22
21
|
p: 24
|
|
23
22
|
},
|
|
24
23
|
children: /* @__PURE__ */ r(n, {
|
|
25
24
|
alignItems: "center",
|
|
26
25
|
flexDirection: "row",
|
|
27
26
|
justifyContent: "space-between",
|
|
28
|
-
children: [/* @__PURE__ */ r(n, { children: [/* @__PURE__ */ e(
|
|
29
|
-
variant:
|
|
30
|
-
children:
|
|
27
|
+
children: [/* @__PURE__ */ r(n, { children: [/* @__PURE__ */ e(w, {
|
|
28
|
+
variant: "h3",
|
|
29
|
+
children: f()
|
|
31
30
|
}), /* @__PURE__ */ e(v, {
|
|
32
31
|
color: "text.secondary",
|
|
33
32
|
children: o.heres_your_spending_overview
|
|
34
33
|
})] }), /* @__PURE__ */ r(n, {
|
|
35
34
|
flexDirection: "row",
|
|
36
|
-
children: [
|
|
35
|
+
children: [l.show_connections_widget_in_master && /* @__PURE__ */ e(_, { handleConnectClick: () => c(!0) }), /* @__PURE__ */ e(u, {})]
|
|
37
36
|
})]
|
|
38
37
|
})
|
|
39
|
-
}), i && /* @__PURE__ */ e(
|
|
38
|
+
}), i && /* @__PURE__ */ e(h, {
|
|
40
39
|
onClose: () => c(!1),
|
|
41
40
|
showConnectWidget: i,
|
|
42
|
-
title:
|
|
41
|
+
title: m.mini_title
|
|
43
42
|
})] });
|
|
44
|
-
},
|
|
43
|
+
}, z = C(b);
|
|
45
44
|
export {
|
|
46
|
-
|
|
45
|
+
z as default
|
|
47
46
|
};
|
|
48
47
|
|
|
49
48
|
//# sourceMappingURL=Greeting.es.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Greeting.es.js","names":[],"sources":["../../src/dashboard/Greeting.tsx"],"sourcesContent":["import React from 'react'\nimport { observer } from 'mobx-react-lite'\n\nimport Stack from '@mui/material/Stack'\nimport Paper from '@mui/material/Paper'\n\nimport { H2, P } from '@mxenabled/mxui'\
|
|
1
|
+
{"version":3,"file":"Greeting.es.js","names":[],"sources":["../../src/dashboard/Greeting.tsx"],"sourcesContent":["import React from 'react'\nimport { observer } from 'mobx-react-lite'\n\nimport Stack from '@mui/material/Stack'\nimport Paper from '@mui/material/Paper'\n\nimport { H2, P } from '@mxenabled/mxui'\n\nimport { ConnectDrawer, useAppConfig, useGlobalCopyStore, useScreenSize } from '../common'\n\nimport AddAccounts from '../common/components/addaccounts/AddAccounts'\nimport { GlobalAccountFilter } from '../common/components/GlobalAccountFilter'\n\nconst Greeting = () => {\n const [showConnectWidget, setShowConnectWidget] = React.useState(false)\n\n const { common: commonCopy, connect: connectCopy } = useGlobalCopyStore()\n const { config } = useAppConfig()\n const { isMobile } = useScreenSize()\n\n const getGreeting = () => {\n const now = new Date()\n const hour = now.getHours()\n\n if (hour > 1 && hour < 12) {\n return commonCopy.good_morning\n } else if (hour >= 12 && hour < 18) {\n return commonCopy.good_afternoon\n } else {\n return commonCopy.good_evening\n }\n }\n\n return (\n <React.Fragment>\n <Paper sx={{ gap: 12, mb: isMobile ? 24 : 0, p: 24 }}>\n <Stack alignItems=\"center\" flexDirection=\"row\" justifyContent=\"space-between\">\n <Stack>\n <H2 variant=\"h3\">{getGreeting()}</H2>\n <P color=\"text.secondary\">{commonCopy.heres_your_spending_overview}</P>\n </Stack>\n <Stack flexDirection=\"row\">\n {config.show_connections_widget_in_master && (\n <AddAccounts handleConnectClick={() => setShowConnectWidget(true)} />\n )}\n <GlobalAccountFilter />\n </Stack>\n </Stack>\n </Paper>\n {showConnectWidget && (\n <ConnectDrawer\n onClose={() => setShowConnectWidget(false)}\n showConnectWidget={showConnectWidget}\n title={connectCopy.mini_title}\n />\n )}\n </React.Fragment>\n )\n}\n\nexport default observer(Greeting)\n"],"mappings":";;;;;;;;;;;AAaA,IAAM,IAAA,MAAiB;AACrB,QAAM,CAAC,GAAmB,CAAA,IAAwB,EAAM,SAAS,EAAK,GAEhE,EAAE,QAAQ,GAAY,SAAS,EAAA,IAAgB,EAAmB,GAClE,EAAE,QAAA,EAAA,IAAW,EAAa,GAC1B,EAAE,UAAA,EAAA,IAAa,EAAc,GAE7B,IAAA,MAAoB;AAExB,UAAM,KAAO,oBADG,KACH,GAAI,SAAS;AAE1B,WAAI,IAAO,KAAK,IAAO,KACd,EAAW,eACT,KAAQ,MAAM,IAAO,KACvB,EAAW,iBAEX,EAAW;AAAA,EAEtB;AAEA,SACE,gBAAA,EAAC,EAAM,UAAP,EAAA,UAAA,CACE,gBAAA,EAAC,GAAD;AAAA,IAAO,IAAI;AAAA,MAAE,KAAK;AAAA,MAAI,IAAI,IAAW,KAAK;AAAA,MAAG,GAAG;AAAA,IAAG;AAAA,IACjD,UAAA,gBAAA,EAAC,GAAD;AAAA,MAAO,YAAW;AAAA,MAAS,eAAc;AAAA,MAAM,gBAAe;AAAA,MAA9D,UAAA,CACE,gBAAA,EAAC,GAAD,EAAA,UAAA,CACE,gBAAA,EAAC,GAAD;AAAA,QAAI,SAAQ;AAAA,QAAM,UAAA,EAAY;AAAA,MAAM,CAAA,GACpC,gBAAA,EAAC,GAAD;AAAA,QAAG,OAAM;AAAA,QAAkB,UAAA,EAAW;AAAA,MAAgC,CAAA,CACjE,EAAA,CAAA,GACP,gBAAA,EAAC,GAAD;AAAA,QAAO,eAAc;AAAA,QAArB,UAAA,CACG,EAAO,qCACN,gBAAA,EAAC,GAAD,EAAa,oBAAA,MAA0B,EAAqB,EAAI,EAAI,CAAA,GAEtE,gBAAA,EAAC,GAAD,CAAsB,CAAA,CACjB;AAAA,MACF,CAAA,CAAA;AAAA;EACF,CAAA,GACN,KACC,gBAAA,EAAC,GAAD;AAAA,IACE,SAAA,MAAe,EAAqB,EAAK;AAAA,IACtB,mBAAA;AAAA,IACnB,OAAO,EAAY;AAAA,EACpB,CAAA,CAEW,EAAA,CAAA;AAEpB,GAEA,IAAe,EAAS,CAAQ"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { default as React } from 'react';
|
|
2
2
|
interface ProfileFormProps {
|
|
3
3
|
availableWidth?: number;
|
|
4
|
-
|
|
4
|
+
handleOnLeaveClick?: () => void;
|
|
5
5
|
}
|
|
6
6
|
declare const _default: React.FunctionComponent<ProfileFormProps>;
|
|
7
7
|
export default _default;
|
|
@@ -1,178 +1,185 @@
|
|
|
1
|
-
import { useAppConfig as
|
|
2
|
-
import { useScreenSize as
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
1
|
+
import { useAppConfig as B, useGlobalCopyStore as F, useSettingsStore as L, useUserStore as M } from "../../../common/context/hooks.es.js";
|
|
2
|
+
import { useScreenSize as R } from "../../../common/hooks/useScreenSize.es.js";
|
|
3
|
+
import z from "../../../common/components/dialog/Dialog.es.js";
|
|
4
|
+
import I from "./actions/ResetPasswordAction.es.js";
|
|
5
|
+
import N from "./actions/VerifyEmailAction.es.js";
|
|
6
|
+
import j from "./actions/VerifyPhoneAction.es.js";
|
|
6
7
|
import p from "react";
|
|
7
|
-
import { observer as
|
|
8
|
-
import
|
|
9
|
-
import { H3 as
|
|
10
|
-
import
|
|
11
|
-
import { Fragment as
|
|
12
|
-
import { alpha as b, useTheme as
|
|
13
|
-
import
|
|
14
|
-
import { getUnixTime as
|
|
15
|
-
import
|
|
16
|
-
import { AdapterDateFns as
|
|
17
|
-
import { DatePicker as
|
|
18
|
-
import { LocalizationProvider as
|
|
19
|
-
var
|
|
20
|
-
const
|
|
21
|
-
first_name:
|
|
22
|
-
last_name:
|
|
23
|
-
email:
|
|
24
|
-
phone:
|
|
25
|
-
birthday:
|
|
26
|
-
postal_code:
|
|
27
|
-
credit_score:
|
|
28
|
-
}), [
|
|
8
|
+
import { observer as H } from "mobx-react-lite";
|
|
9
|
+
import l from "@mui/material/Stack";
|
|
10
|
+
import { H3 as J, P as O } from "@mxenabled/mxui";
|
|
11
|
+
import $ from "@mui/material/Button";
|
|
12
|
+
import { Fragment as G, jsx as t, jsxs as i } from "react/jsx-runtime";
|
|
13
|
+
import { alpha as b, useTheme as K } from "@mui/material/styles";
|
|
14
|
+
import Y from "@mui/material/Box";
|
|
15
|
+
import { getUnixTime as q } from "date-fns/getUnixTime";
|
|
16
|
+
import d from "@mui/material/TextField";
|
|
17
|
+
import { AdapterDateFns as Q } from "@mui/x-date-pickers/AdapterDateFnsV3";
|
|
18
|
+
import { DatePicker as W } from "@mui/x-date-pickers";
|
|
19
|
+
import { LocalizationProvider as X } from "@mui/x-date-pickers/LocalizationProvider";
|
|
20
|
+
var Z = ({ availableWidth: C, handleOnLeaveClick: f }) => {
|
|
21
|
+
const u = K(), { common: w, settings: o } = F(), { isMobile: c } = R(C), { config: h } = B(), { updateUser: S } = L(), { user: r } = M(), [a, U] = p.useState({
|
|
22
|
+
first_name: r.first_name,
|
|
23
|
+
last_name: r.last_name,
|
|
24
|
+
email: r.email,
|
|
25
|
+
phone: r.phone,
|
|
26
|
+
birthday: r.birthday,
|
|
27
|
+
postal_code: r.postal_code,
|
|
28
|
+
credit_score: r.credit_score
|
|
29
|
+
}), [m, y] = p.useState(!1), [P, g] = p.useState(!1), _ = p.useRef(null), v = a.email && !r.email_is_verified && !m, x = a.phone && !r.phone_is_verified && !m;
|
|
29
30
|
p.useEffect(() => {
|
|
30
|
-
if (
|
|
31
|
-
const e = (
|
|
32
|
-
_.current && !_.current.contains(
|
|
31
|
+
if (f) {
|
|
32
|
+
const e = (s) => {
|
|
33
|
+
_.current && !_.current.contains(s.target) && m && g(!0);
|
|
33
34
|
};
|
|
34
35
|
return document.addEventListener("mousedown", e), () => {
|
|
35
36
|
document.removeEventListener("mousedown", e);
|
|
36
37
|
};
|
|
37
38
|
}
|
|
38
|
-
}, [
|
|
39
|
-
const
|
|
40
|
-
if (
|
|
41
|
-
const e = /* @__PURE__ */ new Date(
|
|
42
|
-
return new Date(
|
|
39
|
+
}, [m]);
|
|
40
|
+
const T = () => {
|
|
41
|
+
if (a.birthday) {
|
|
42
|
+
const e = /* @__PURE__ */ new Date(a.birthday * 1e3), s = e.getUTCFullYear(), A = e.getUTCMonth(), E = e.getUTCDate();
|
|
43
|
+
return new Date(s, A, E);
|
|
43
44
|
}
|
|
44
|
-
},
|
|
45
|
-
await
|
|
46
|
-
...
|
|
47
|
-
...
|
|
48
|
-
}),
|
|
49
|
-
},
|
|
50
|
-
g(!1),
|
|
51
|
-
},
|
|
45
|
+
}, V = async () => {
|
|
46
|
+
await S({
|
|
47
|
+
...r,
|
|
48
|
+
...a
|
|
49
|
+
}), y(!1);
|
|
50
|
+
}, D = () => {
|
|
51
|
+
g(!1), f && f();
|
|
52
|
+
}, k = () => {
|
|
52
53
|
g(!1);
|
|
53
54
|
}, n = (e) => {
|
|
54
|
-
const
|
|
55
|
-
...
|
|
55
|
+
const s = {
|
|
56
|
+
...a,
|
|
56
57
|
...e
|
|
57
58
|
};
|
|
58
|
-
|
|
59
|
-
...
|
|
60
|
-
...
|
|
61
|
-
}) !== JSON.stringify(
|
|
59
|
+
U(s), y(JSON.stringify({
|
|
60
|
+
...r,
|
|
61
|
+
...s
|
|
62
|
+
}) !== JSON.stringify(r));
|
|
62
63
|
};
|
|
63
|
-
return /* @__PURE__ */ i(
|
|
64
|
+
return /* @__PURE__ */ i(G, { children: [/* @__PURE__ */ i(Y, {
|
|
64
65
|
component: "form",
|
|
65
66
|
ref: _,
|
|
66
67
|
sx: {
|
|
67
68
|
backgroundColor: "background.paper",
|
|
68
69
|
p: 24,
|
|
69
|
-
|
|
70
|
-
"& .MuiTextField-root": { width: h ? 272 : v ? 328 : y ? 483 : 352 }
|
|
70
|
+
"& .MuiTextField-root": { flex: 1 }
|
|
71
71
|
},
|
|
72
72
|
children: [
|
|
73
|
-
/* @__PURE__ */ t(
|
|
74
|
-
/* @__PURE__ */ t(
|
|
73
|
+
/* @__PURE__ */ t(J, { children: o.personal_details }),
|
|
74
|
+
/* @__PURE__ */ t(O, {
|
|
75
75
|
variant: "body1",
|
|
76
76
|
children: o.update_information
|
|
77
77
|
}),
|
|
78
|
-
/* @__PURE__ */ i(
|
|
79
|
-
direction:
|
|
80
|
-
spacing:
|
|
78
|
+
/* @__PURE__ */ i(l, {
|
|
79
|
+
direction: c ? "column" : "row",
|
|
80
|
+
spacing: 24,
|
|
81
81
|
sx: {
|
|
82
|
-
mb:
|
|
83
|
-
pt:
|
|
82
|
+
mb: 24,
|
|
83
|
+
pt: 24
|
|
84
84
|
},
|
|
85
|
-
children: [/* @__PURE__ */ t(
|
|
86
|
-
defaultValue:
|
|
85
|
+
children: [/* @__PURE__ */ t(d, {
|
|
86
|
+
defaultValue: a.first_name,
|
|
87
87
|
label: o.first_name,
|
|
88
88
|
onChange: (e) => n({ first_name: e.target.value })
|
|
89
|
-
}), /* @__PURE__ */ t(
|
|
90
|
-
defaultValue:
|
|
89
|
+
}), /* @__PURE__ */ t(d, {
|
|
90
|
+
defaultValue: a.last_name,
|
|
91
91
|
label: o.last_name,
|
|
92
92
|
onChange: (e) => n({ last_name: e.target.value })
|
|
93
93
|
})]
|
|
94
94
|
}),
|
|
95
|
-
/* @__PURE__ */ i(
|
|
96
|
-
direction:
|
|
97
|
-
children: [
|
|
95
|
+
/* @__PURE__ */ i(l, {
|
|
96
|
+
direction: c ? "column" : "row",
|
|
97
|
+
children: [h.display_email_edit_field_in_settings && /* @__PURE__ */ i(l, {
|
|
98
98
|
sx: {
|
|
99
|
-
|
|
100
|
-
|
|
99
|
+
flex: 1,
|
|
100
|
+
mb: v ? 20 : 24,
|
|
101
|
+
mr: c ? 0 : 24
|
|
101
102
|
},
|
|
102
|
-
children: [/* @__PURE__ */ t(
|
|
103
|
-
defaultValue:
|
|
103
|
+
children: [/* @__PURE__ */ t(d, {
|
|
104
|
+
defaultValue: a.email,
|
|
104
105
|
label: o.email_address,
|
|
105
106
|
onChange: (e) => n({ email: e.target.value })
|
|
106
|
-
}),
|
|
107
|
-
}),
|
|
108
|
-
sx: {
|
|
109
|
-
|
|
110
|
-
|
|
107
|
+
}), v && /* @__PURE__ */ t(N, {})]
|
|
108
|
+
}), h.display_sms_edit_field_in_settings && /* @__PURE__ */ i(l, {
|
|
109
|
+
sx: {
|
|
110
|
+
flex: 1,
|
|
111
|
+
mb: x ? 20 : 24
|
|
112
|
+
},
|
|
113
|
+
children: [/* @__PURE__ */ t(d, {
|
|
114
|
+
defaultValue: a.phone,
|
|
111
115
|
label: o.mobile_number,
|
|
112
116
|
onChange: (e) => n({ phone: e.target.value }),
|
|
113
117
|
type: "tel"
|
|
114
|
-
}),
|
|
118
|
+
}), x && /* @__PURE__ */ t(j, {})]
|
|
115
119
|
})]
|
|
116
120
|
}),
|
|
117
|
-
/* @__PURE__ */ i(
|
|
118
|
-
direction:
|
|
119
|
-
spacing:
|
|
120
|
-
sx: { mb:
|
|
121
|
-
children: [/* @__PURE__ */ t(
|
|
122
|
-
dateAdapter:
|
|
123
|
-
children: /* @__PURE__ */ t(
|
|
121
|
+
/* @__PURE__ */ i(l, {
|
|
122
|
+
direction: c ? "column" : "row",
|
|
123
|
+
spacing: 24,
|
|
124
|
+
sx: { mb: 24 },
|
|
125
|
+
children: [/* @__PURE__ */ t(X, {
|
|
126
|
+
dateAdapter: Q,
|
|
127
|
+
children: /* @__PURE__ */ t(W, {
|
|
124
128
|
label: o.birthdate,
|
|
125
|
-
onChange: (e) => n({ birthday:
|
|
129
|
+
onChange: (e) => n({ birthday: q(e) }),
|
|
126
130
|
slotProps: {
|
|
127
131
|
nextIconButton: { sx: {
|
|
128
132
|
color: "primary.main",
|
|
129
|
-
"&:hover": { backgroundColor: b(
|
|
133
|
+
"&:hover": { backgroundColor: b(u.palette.primary.light, 0.1) }
|
|
130
134
|
} },
|
|
131
135
|
previousIconButton: { sx: {
|
|
132
136
|
color: "primary.main",
|
|
133
|
-
"&:hover": { backgroundColor: b(
|
|
137
|
+
"&:hover": { backgroundColor: b(u.palette.primary.light, 0.1) }
|
|
134
138
|
} }
|
|
135
139
|
},
|
|
136
140
|
sx: {
|
|
137
141
|
width: "100%",
|
|
138
142
|
"& .MuiIconButton-edgeEnd": {
|
|
139
143
|
color: "primary.main",
|
|
140
|
-
"&:hover": { backgroundColor: b(
|
|
144
|
+
"&:hover": { backgroundColor: b(u.palette.primary.light, 0.1) }
|
|
141
145
|
}
|
|
142
146
|
},
|
|
143
|
-
value:
|
|
147
|
+
value: T()
|
|
144
148
|
})
|
|
145
|
-
}), /* @__PURE__ */ t(
|
|
146
|
-
defaultValue:
|
|
149
|
+
}), /* @__PURE__ */ t(d, {
|
|
150
|
+
defaultValue: a.postal_code,
|
|
147
151
|
label: o.zip_code,
|
|
148
152
|
onChange: (e) => n({ postal_code: e.target.value })
|
|
149
153
|
})]
|
|
150
154
|
}),
|
|
151
|
-
/* @__PURE__ */ i(
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
155
|
+
/* @__PURE__ */ i(l, { children: [
|
|
156
|
+
/* @__PURE__ */ t(d, {
|
|
157
|
+
defaultValue: a.credit_score,
|
|
158
|
+
label: o.credit_score,
|
|
159
|
+
onChange: (e) => n({ credit_score: Number(e.target.value) })
|
|
160
|
+
}),
|
|
161
|
+
h.display_password_options_in_settings && /* @__PURE__ */ t(I, {}),
|
|
162
|
+
/* @__PURE__ */ t($, {
|
|
163
|
+
disabled: !m,
|
|
164
|
+
onClick: V,
|
|
165
|
+
sx: { width: c ? "100%" : 124 },
|
|
166
|
+
variant: "contained",
|
|
167
|
+
children: w.save_button
|
|
168
|
+
})
|
|
169
|
+
] })
|
|
163
170
|
]
|
|
164
|
-
}), /* @__PURE__ */ t(
|
|
171
|
+
}), /* @__PURE__ */ t(z, {
|
|
165
172
|
copy: { title: o.discard_changes },
|
|
166
|
-
isOpen:
|
|
167
|
-
onClose:
|
|
168
|
-
onSecondaryAction:
|
|
173
|
+
isOpen: P,
|
|
174
|
+
onClose: k,
|
|
175
|
+
onSecondaryAction: D,
|
|
169
176
|
primaryText: o.keep_editing,
|
|
170
177
|
secondaryText: o.leave,
|
|
171
178
|
children: o.discard_changes_message
|
|
172
179
|
})] });
|
|
173
|
-
},
|
|
180
|
+
}, ye = H(Z);
|
|
174
181
|
export {
|
|
175
|
-
|
|
182
|
+
ye as default
|
|
176
183
|
};
|
|
177
184
|
|
|
178
185
|
//# sourceMappingURL=ProfileTab.es.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ProfileTab.es.js","names":[],"sources":["../../../../src/settings/components/profile/ProfileTab.tsx"],"sourcesContent":["/* eslint-disable no-nested-ternary */\n\nimport React from 'react'\nimport { observer } from 'mobx-react-lite'\nimport { getUnixTime } from 'date-fns/getUnixTime'\n\nimport { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFnsV3'\nimport { DatePicker } from '@mui/x-date-pickers'\nimport { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'\n\nimport { alpha, useTheme } from '@mui/material/styles'\nimport Box from '@mui/material/Box'\nimport Button from '@mui/material/Button'\nimport Stack from '@mui/material/Stack'\nimport TextField from '@mui/material/TextField'\n\nimport { H3, P } from '@mxenabled/mxui'\n\nimport {\n useAppConfig,\n useGlobalCopyStore,\n useScreenSize,\n useSettingsStore,\n useUserStore,\n Dialog,\n} from '../../../common'\nimport { type EditableUser } from '../../../core'\nimport VerifyEmailAction from './actions/VerifyEmailAction'\nimport VerifyPhoneAction from './actions/VerifyPhoneAction'\n\ninterface ProfileFormProps {\n availableWidth?: number\n handleOnLeavClick?: () => void\n}\n\ntype UserInput = {\n [U in keyof EditableUser]: EditableUser[U]\n}\n\nconst ProfileForm: React.FC<ProfileFormProps> = ({ availableWidth, handleOnLeavClick }) => {\n const theme = useTheme()\n const { common: commonCopy, settings: settingsCopy } = useGlobalCopyStore()\n const { isDesktop, isMobile, isSmallMobile, isTablet } = useScreenSize(availableWidth)\n const { config } = useAppConfig()\n const { updateUser } = useSettingsStore()\n const { user } = useUserStore()\n\n const [modifiedUser, setModifiedUser] = React.useState<EditableUser>({\n first_name: user.first_name,\n last_name: user.last_name,\n email: user.email,\n phone: user.phone,\n birthday: user.birthday,\n postal_code: user.postal_code,\n credit_score: user.credit_score,\n })\n const [hasUnsavedChanges, setHasUnsavedChanges] = React.useState(false)\n const [showLeaveDialog, setShowLeaveDialog] = React.useState(false)\n const boxRef = React.useRef<HTMLDivElement>(null)\n\n const showVerifyEmail = modifiedUser.email && !user.email_is_verified && !hasUnsavedChanges\n const showVerifyPhone = modifiedUser.phone && !user.phone_is_verified && !hasUnsavedChanges\n\n React.useEffect(() => {\n if (handleOnLeavClick) {\n const handleClickOutside = (event: MouseEvent) => {\n if (boxRef.current && !boxRef.current.contains(event.target as Node) && hasUnsavedChanges) {\n setShowLeaveDialog(true)\n }\n }\n\n document.addEventListener('mousedown', handleClickOutside)\n return () => {\n document.removeEventListener('mousedown', handleClickOutside)\n }\n }\n return undefined\n }, [hasUnsavedChanges])\n\n // eslint-disable-next-line consistent-return\n const formatReadableBirthday = () => {\n if (modifiedUser.birthday) {\n const utc = new Date(modifiedUser.birthday * 1000)\n const year = utc.getUTCFullYear()\n const month = utc.getUTCMonth()\n const day = utc.getUTCDate()\n return new Date(year, month, day)\n }\n }\n\n const handleSave = async () => {\n await updateUser({ ...user, ...modifiedUser })\n setHasUnsavedChanges(false)\n }\n\n const handleLeaveDialog = () => {\n setShowLeaveDialog(false)\n\n if (handleOnLeavClick) {\n handleOnLeavClick()\n }\n }\n\n const handleKeepEditing = () => {\n setShowLeaveDialog(false)\n }\n\n const handleInput = (update: UserInput) => {\n const changedUser = {\n ...modifiedUser,\n ...update,\n }\n setModifiedUser(changedUser)\n setHasUnsavedChanges(JSON.stringify({ ...user, ...changedUser }) !== JSON.stringify(user))\n }\n\n return (\n <>\n <Box\n component=\"form\"\n ref={boxRef}\n sx={{\n backgroundColor: 'background.paper',\n p: 24,\n width: isSmallMobile ? 320 : isTablet ? 680 : isDesktop ? 990 : 400,\n '& .MuiTextField-root': {\n width: isSmallMobile ? 272 : isTablet ? 328 : isDesktop ? 483 : 352,\n },\n }}\n >\n <H3>{settingsCopy.personal_details}</H3>\n <P variant=\"body1\">{settingsCopy.update_information}</P>\n <Stack\n direction={isMobile ? 'column' : 'row'}\n spacing={isMobile ? 44 : 24}\n sx={{ mb: 44, pt: 32 }}\n >\n <TextField\n defaultValue={modifiedUser.first_name}\n label={settingsCopy.first_name}\n onChange={(e) => handleInput({ first_name: e.target.value })}\n />\n <TextField\n defaultValue={modifiedUser.last_name}\n label={settingsCopy.last_name}\n onChange={(e) => handleInput({ last_name: e.target.value })}\n />\n </Stack>\n <Stack direction={isMobile ? 'column' : 'row'}>\n {config.display_email_edit_field_in_settings && (\n <Stack sx={{ mb: showVerifyEmail ? 20 : 44, mr: isMobile ? 0 : 24 }}>\n <TextField\n defaultValue={modifiedUser.email}\n label={settingsCopy.email_address}\n onChange={(e) => handleInput({ email: e.target.value })}\n />\n {showVerifyEmail && <VerifyEmailAction />}\n </Stack>\n )}\n {config.display_sms_edit_field_in_settings && (\n <Stack sx={{ mb: showVerifyPhone ? 20 : 44 }}>\n <TextField\n defaultValue={modifiedUser.phone}\n label={settingsCopy.mobile_number}\n onChange={(e) => handleInput({ phone: e.target.value })}\n type=\"tel\"\n />\n {showVerifyPhone && <VerifyPhoneAction />}\n </Stack>\n )}\n </Stack>\n <Stack direction={isMobile ? 'column' : 'row'} spacing={isMobile ? 44 : 24} sx={{ mb: 44 }}>\n <LocalizationProvider dateAdapter={AdapterDateFns}>\n <DatePicker\n label={settingsCopy.birthdate}\n onChange={(value) => handleInput({ birthday: getUnixTime(value as Date) })}\n slotProps={{\n nextIconButton: {\n sx: {\n color: 'primary.main',\n '&:hover': { backgroundColor: alpha(theme.palette.primary.light, 0.1) },\n },\n },\n previousIconButton: {\n sx: {\n color: 'primary.main',\n '&:hover': { backgroundColor: alpha(theme.palette.primary.light, 0.1) },\n },\n },\n }}\n sx={{\n width: '100%',\n '& .MuiIconButton-edgeEnd': {\n color: 'primary.main',\n '&:hover': { backgroundColor: alpha(theme.palette.primary.light, 0.1) },\n },\n }}\n value={formatReadableBirthday()}\n />\n </LocalizationProvider>\n <TextField\n defaultValue={modifiedUser.postal_code}\n label={settingsCopy.zip_code}\n onChange={(e) => handleInput({ postal_code: e.target.value })}\n />\n </Stack>\n <Stack>\n <TextField\n defaultValue={modifiedUser.credit_score}\n label={settingsCopy.credit_score}\n onChange={(e) => handleInput({ credit_score: Number(e.target.value) })}\n sx={{ mb: 44 }}\n />\n <Button\n disabled={!hasUnsavedChanges}\n onClick={handleSave}\n sx={{ width: isSmallMobile ? 272 : 124 }}\n variant=\"contained\"\n >\n {commonCopy.save_button}\n </Button>\n </Stack>\n </Box>\n <Dialog\n copy={{ title: settingsCopy.discard_changes }}\n isOpen={showLeaveDialog}\n onClose={handleKeepEditing}\n onSecondaryAction={handleLeaveDialog}\n primaryText={settingsCopy.keep_editing}\n secondaryText={settingsCopy.leave}\n >\n {settingsCopy.discard_changes_message}\n </Dialog>\n </>\n )\n}\n\nexport default observer(ProfileForm)\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ProfileTab.es.js","names":[],"sources":["../../../../src/settings/components/profile/ProfileTab.tsx"],"sourcesContent":["import React from 'react'\nimport { observer } from 'mobx-react-lite'\nimport { getUnixTime } from 'date-fns/getUnixTime'\n\nimport { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFnsV3'\nimport { DatePicker } from '@mui/x-date-pickers'\nimport { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider'\n\nimport { alpha, useTheme } from '@mui/material/styles'\nimport Box from '@mui/material/Box'\nimport Button from '@mui/material/Button'\nimport Stack from '@mui/material/Stack'\nimport TextField from '@mui/material/TextField'\n\nimport { H3, P } from '@mxenabled/mxui'\n\nimport {\n useAppConfig,\n useGlobalCopyStore,\n useScreenSize,\n useSettingsStore,\n useUserStore,\n Dialog,\n} from '../../../common'\nimport { type EditableUser } from '../../../core'\nimport ResetPasswordAction from './actions/ResetPasswordAction'\nimport VerifyEmailAction from './actions/VerifyEmailAction'\nimport VerifyPhoneAction from './actions/VerifyPhoneAction'\n\ninterface ProfileFormProps {\n availableWidth?: number\n handleOnLeaveClick?: () => void\n}\n\ntype UserInput = {\n [U in keyof EditableUser]: EditableUser[U]\n}\n\nconst ProfileForm: React.FC<ProfileFormProps> = ({ availableWidth, handleOnLeaveClick }) => {\n const theme = useTheme()\n const { common: commonCopy, settings: settingsCopy } = useGlobalCopyStore()\n const { isMobile } = useScreenSize(availableWidth)\n const { config } = useAppConfig()\n const { updateUser } = useSettingsStore()\n const { user } = useUserStore()\n\n const [modifiedUser, setModifiedUser] = React.useState<EditableUser>({\n first_name: user.first_name,\n last_name: user.last_name,\n email: user.email,\n phone: user.phone,\n birthday: user.birthday,\n postal_code: user.postal_code,\n credit_score: user.credit_score,\n })\n const [hasUnsavedChanges, setHasUnsavedChanges] = React.useState(false)\n const [showLeaveDialog, setShowLeaveDialog] = React.useState(false)\n const boxRef = React.useRef<HTMLDivElement>(null)\n\n const showVerifyEmail = modifiedUser.email && !user.email_is_verified && !hasUnsavedChanges\n const showVerifyPhone = modifiedUser.phone && !user.phone_is_verified && !hasUnsavedChanges\n\n React.useEffect(() => {\n if (handleOnLeaveClick) {\n const handleClickOutside = (event: MouseEvent) => {\n if (boxRef.current && !boxRef.current.contains(event.target as Node) && hasUnsavedChanges) {\n setShowLeaveDialog(true)\n }\n }\n\n document.addEventListener('mousedown', handleClickOutside)\n return () => {\n document.removeEventListener('mousedown', handleClickOutside)\n }\n }\n return undefined\n }, [hasUnsavedChanges])\n\n // eslint-disable-next-line consistent-return\n const formatReadableBirthday = () => {\n if (modifiedUser.birthday) {\n const utc = new Date(modifiedUser.birthday * 1000)\n const year = utc.getUTCFullYear()\n const month = utc.getUTCMonth()\n const day = utc.getUTCDate()\n return new Date(year, month, day)\n }\n }\n\n const handleSave = async () => {\n await updateUser({ ...user, ...modifiedUser })\n setHasUnsavedChanges(false)\n }\n\n const handleLeaveDialog = () => {\n setShowLeaveDialog(false)\n\n if (handleOnLeaveClick) {\n handleOnLeaveClick()\n }\n }\n\n const handleKeepEditing = () => {\n setShowLeaveDialog(false)\n }\n\n const handleInput = (update: UserInput) => {\n const changedUser = {\n ...modifiedUser,\n ...update,\n }\n setModifiedUser(changedUser)\n setHasUnsavedChanges(JSON.stringify({ ...user, ...changedUser }) !== JSON.stringify(user))\n }\n\n return (\n <>\n <Box\n component=\"form\"\n ref={boxRef}\n sx={{\n backgroundColor: 'background.paper',\n p: 24,\n '& .MuiTextField-root': {\n flex: 1,\n },\n }}\n >\n <H3>{settingsCopy.personal_details}</H3>\n <P variant=\"body1\">{settingsCopy.update_information}</P>\n <Stack direction={isMobile ? 'column' : 'row'} spacing={24} sx={{ mb: 24, pt: 24 }}>\n <TextField\n defaultValue={modifiedUser.first_name}\n label={settingsCopy.first_name}\n onChange={(e) => handleInput({ first_name: e.target.value })}\n />\n <TextField\n defaultValue={modifiedUser.last_name}\n label={settingsCopy.last_name}\n onChange={(e) => handleInput({ last_name: e.target.value })}\n />\n </Stack>\n <Stack direction={isMobile ? 'column' : 'row'}>\n {config.display_email_edit_field_in_settings && (\n <Stack sx={{ flex: 1, mb: showVerifyEmail ? 20 : 24, mr: isMobile ? 0 : 24 }}>\n <TextField\n defaultValue={modifiedUser.email}\n label={settingsCopy.email_address}\n onChange={(e) => handleInput({ email: e.target.value })}\n />\n {showVerifyEmail && <VerifyEmailAction />}\n </Stack>\n )}\n {config.display_sms_edit_field_in_settings && (\n <Stack sx={{ flex: 1, mb: showVerifyPhone ? 20 : 24 }}>\n <TextField\n defaultValue={modifiedUser.phone}\n label={settingsCopy.mobile_number}\n onChange={(e) => handleInput({ phone: e.target.value })}\n type=\"tel\"\n />\n {showVerifyPhone && <VerifyPhoneAction />}\n </Stack>\n )}\n </Stack>\n <Stack direction={isMobile ? 'column' : 'row'} spacing={24} sx={{ mb: 24 }}>\n <LocalizationProvider dateAdapter={AdapterDateFns}>\n <DatePicker\n label={settingsCopy.birthdate}\n onChange={(value) => handleInput({ birthday: getUnixTime(value as Date) })}\n slotProps={{\n nextIconButton: {\n sx: {\n color: 'primary.main',\n '&:hover': { backgroundColor: alpha(theme.palette.primary.light, 0.1) },\n },\n },\n previousIconButton: {\n sx: {\n color: 'primary.main',\n '&:hover': { backgroundColor: alpha(theme.palette.primary.light, 0.1) },\n },\n },\n }}\n sx={{\n width: '100%',\n '& .MuiIconButton-edgeEnd': {\n color: 'primary.main',\n '&:hover': { backgroundColor: alpha(theme.palette.primary.light, 0.1) },\n },\n }}\n value={formatReadableBirthday()}\n />\n </LocalizationProvider>\n <TextField\n defaultValue={modifiedUser.postal_code}\n label={settingsCopy.zip_code}\n onChange={(e) => handleInput({ postal_code: e.target.value })}\n />\n </Stack>\n <Stack>\n <TextField\n defaultValue={modifiedUser.credit_score}\n label={settingsCopy.credit_score}\n onChange={(e) => handleInput({ credit_score: Number(e.target.value) })}\n />\n {config.display_password_options_in_settings && <ResetPasswordAction />}\n <Button\n disabled={!hasUnsavedChanges}\n onClick={handleSave}\n sx={{ width: isMobile ? '100%' : 124 }}\n variant=\"contained\"\n >\n {commonCopy.save_button}\n </Button>\n </Stack>\n </Box>\n <Dialog\n copy={{ title: settingsCopy.discard_changes }}\n isOpen={showLeaveDialog}\n onClose={handleKeepEditing}\n onSecondaryAction={handleLeaveDialog}\n primaryText={settingsCopy.keep_editing}\n secondaryText={settingsCopy.leave}\n >\n {settingsCopy.discard_changes_message}\n </Dialog>\n </>\n )\n}\n\nexport default observer(ProfileForm)\n"],"mappings":"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"}
|