chore: use monorepo organization
This commit is contained in:
parent
deaf7d6ecc
commit
a687827f7e
1099 changed files with 8184 additions and 11535 deletions
255
packages/admin-ui/src/pages/Locales/Locales.jsx
Normal file
255
packages/admin-ui/src/pages/Locales/Locales.jsx
Normal file
|
|
@ -0,0 +1,255 @@
|
|||
import { useQuery, useMutation, gql } from '@apollo/client'
|
||||
import * as R from 'ramda'
|
||||
import React, { useState } from 'react'
|
||||
import Modal from 'src/components/Modal'
|
||||
import { HelpTooltip } from 'src/components/Tooltip'
|
||||
import Section from 'src/components/layout/Section'
|
||||
import TitleSection from 'src/components/layout/TitleSection'
|
||||
import { P } from 'src/components/typography'
|
||||
import _schemas from 'src/pages/Services/schemas'
|
||||
import Wizard from 'src/pages/Wallet/Wizard'
|
||||
import { WalletSchema } from 'src/pages/Wallet/helper'
|
||||
|
||||
import { Link, SupportLinkButton } from 'src/components/buttons'
|
||||
import { Table as EditableTable } from 'src/components/editableTable'
|
||||
import { fromNamespace, toNamespace, namespaces } from 'src/utils/config'
|
||||
|
||||
import {
|
||||
mainFields,
|
||||
overrides,
|
||||
LocaleSchema,
|
||||
OverridesSchema,
|
||||
localeDefaults,
|
||||
overridesDefaults
|
||||
} from './helper'
|
||||
|
||||
const GET_DATA = gql`
|
||||
query getData {
|
||||
config
|
||||
accounts
|
||||
accountsConfig {
|
||||
code
|
||||
display
|
||||
class
|
||||
cryptos
|
||||
}
|
||||
currencies {
|
||||
code
|
||||
display
|
||||
}
|
||||
countries {
|
||||
code
|
||||
display
|
||||
}
|
||||
cryptoCurrencies {
|
||||
code
|
||||
display
|
||||
isBeta
|
||||
}
|
||||
languages {
|
||||
code
|
||||
display
|
||||
}
|
||||
machines {
|
||||
name
|
||||
deviceId
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const SAVE_CONFIG = gql`
|
||||
mutation Save($config: JSONObject, $accounts: JSONObject) {
|
||||
saveConfig(config: $config)
|
||||
saveAccounts(accounts: $accounts)
|
||||
}
|
||||
`
|
||||
|
||||
const GET_MARKETS = gql`
|
||||
query getMarkets {
|
||||
getMarkets
|
||||
}
|
||||
`
|
||||
|
||||
const FiatCurrencyChangeAlert = ({ open, close, save }) => {
|
||||
return (
|
||||
<Modal
|
||||
title={'Change fiat currency?'}
|
||||
handleClose={close}
|
||||
width={450}
|
||||
height={310}
|
||||
open={open}>
|
||||
<P>
|
||||
Please note that all values you set that were based on your prior fiat
|
||||
currency are still the same. If you need to adjust these to reflect the
|
||||
new fiat currency (such as minimum transaction amounts, fixed fees, and
|
||||
compliance triggers, for example), please do so now.
|
||||
</P>
|
||||
<P>
|
||||
Also, if you have cash-out enabled, you must define new dispenser bill
|
||||
counts for the new currency for cash-out on the new currency to work.
|
||||
</P>
|
||||
<div className="ml-auto">
|
||||
<Link onClick={close} color="secondary">
|
||||
Cancel
|
||||
</Link>
|
||||
<Link className="ml-5" onClick={save} color="primary">
|
||||
Save
|
||||
</Link>
|
||||
</div>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
const Locales = ({ name: SCREEN_KEY }) => {
|
||||
const [wizard, setWizard] = useState(false)
|
||||
const [onChangeFunction, setOnChangeFunction] = useState(null)
|
||||
const [error, setError] = useState(null)
|
||||
const [isEditingDefault, setEditingDefault] = useState(false)
|
||||
const [isEditingOverrides, setEditingOverrides] = useState(false)
|
||||
const { data } = useQuery(GET_DATA)
|
||||
const { data: marketsData } = useQuery(GET_MARKETS)
|
||||
const schemas = _schemas(marketsData?.getMarkets)
|
||||
|
||||
const [saveConfig] = useMutation(SAVE_CONFIG, {
|
||||
onCompleted: () => setWizard(false),
|
||||
refetchQueries: () => ['getData'],
|
||||
onError: error => setError(error)
|
||||
})
|
||||
|
||||
const [dataToSave, setDataToSave] = useState(null)
|
||||
|
||||
const config = data?.config && fromNamespace(SCREEN_KEY)(data.config)
|
||||
const wallets = data?.config && fromNamespace(namespaces.WALLETS)(data.config)
|
||||
|
||||
const accountsConfig = data?.accountsConfig
|
||||
const accounts = data?.accounts ?? []
|
||||
const cryptoCurrencies = data?.cryptoCurrencies ?? []
|
||||
const locale = config && !R.isEmpty(config) ? config : localeDefaults
|
||||
const localeOverrides = locale.overrides ?? []
|
||||
|
||||
const handleSave = it => {
|
||||
const newConfig = toNamespace(SCREEN_KEY)(it.locale[0])
|
||||
|
||||
if (
|
||||
config.fiatCurrency &&
|
||||
newConfig.locale_fiatCurrency !== config.fiatCurrency
|
||||
)
|
||||
return setDataToSave(newConfig)
|
||||
|
||||
return save(newConfig)
|
||||
}
|
||||
|
||||
const save = (config, accounts) => {
|
||||
setDataToSave(null)
|
||||
return saveConfig({ variables: { config, accounts } })
|
||||
}
|
||||
|
||||
const saveOverrides = it => {
|
||||
const config = toNamespace(SCREEN_KEY)(it)
|
||||
setError(null)
|
||||
return saveConfig({ variables: { config } })
|
||||
}
|
||||
|
||||
const onChangeCoin = (prev, curr, setValue) => {
|
||||
const coin = R.difference(curr, prev)[0]
|
||||
if (!coin) return setValue(curr)
|
||||
|
||||
const namespaced = fromNamespace(coin)(wallets)
|
||||
if (!WalletSchema.isValidSync(namespaced)) {
|
||||
setOnChangeFunction(() => () => setValue(curr))
|
||||
setWizard(coin)
|
||||
return
|
||||
}
|
||||
|
||||
setValue(curr)
|
||||
}
|
||||
|
||||
const onEditingDefault = (it, editing) => setEditingDefault(editing)
|
||||
const onEditingOverrides = (it, editing) => setEditingOverrides(editing)
|
||||
|
||||
const wizardSave = (config, accounts) =>
|
||||
save(toNamespace(namespaces.WALLETS)(config), accounts).then(it => {
|
||||
onChangeFunction()
|
||||
setOnChangeFunction(null)
|
||||
return it
|
||||
})
|
||||
|
||||
return (
|
||||
<>
|
||||
<FiatCurrencyChangeAlert
|
||||
open={dataToSave}
|
||||
close={() => setDataToSave(null)}
|
||||
save={() => dataToSave && save(dataToSave)}
|
||||
/>
|
||||
<TitleSection
|
||||
title="Locales"
|
||||
appendix={
|
||||
<HelpTooltip width={320}>
|
||||
<P>
|
||||
For details on configuring languages, please read the relevant
|
||||
knowledgebase article:
|
||||
</P>
|
||||
<SupportLinkButton
|
||||
link="https://support.lamassu.is/hc/en-us/articles/360016257471-Setting-multiple-machine-languages"
|
||||
label="Setting multiple machine languages"
|
||||
bottomSpace="1"
|
||||
/>
|
||||
</HelpTooltip>
|
||||
}
|
||||
/>
|
||||
<Section>
|
||||
<EditableTable
|
||||
title="Default settings"
|
||||
error={error?.message}
|
||||
titleLg
|
||||
name="locale"
|
||||
enableEdit
|
||||
initialValues={locale}
|
||||
save={handleSave}
|
||||
validationSchema={LocaleSchema}
|
||||
data={R.of(locale)}
|
||||
elements={mainFields(data, onChangeCoin)}
|
||||
setEditing={onEditingDefault}
|
||||
forceDisable={isEditingOverrides}
|
||||
/>
|
||||
</Section>
|
||||
<Section>
|
||||
<EditableTable
|
||||
error={error?.message}
|
||||
title="Overrides"
|
||||
titleLg
|
||||
name="overrides"
|
||||
enableDelete
|
||||
enableEdit
|
||||
enableCreate
|
||||
initialValues={overridesDefaults}
|
||||
save={saveOverrides}
|
||||
validationSchema={OverridesSchema}
|
||||
data={localeOverrides ?? []}
|
||||
elements={overrides(data, localeOverrides, onChangeCoin)}
|
||||
disableAdd={R.compose(R.isEmpty, R.difference)(
|
||||
data?.machines.map(m => m.deviceId) ?? [],
|
||||
localeOverrides?.map(o => o.machine) ?? []
|
||||
)}
|
||||
setEditing={onEditingOverrides}
|
||||
forceDisable={isEditingDefault}
|
||||
/>
|
||||
</Section>
|
||||
{wizard && (
|
||||
<Wizard
|
||||
schemas={schemas}
|
||||
coin={R.find(R.propEq('code', wizard))(cryptoCurrencies)}
|
||||
onClose={() => setWizard(false)}
|
||||
save={wizardSave}
|
||||
error={error?.message}
|
||||
cryptoCurrencies={cryptoCurrencies}
|
||||
userAccounts={data?.config?.accounts}
|
||||
accounts={accounts}
|
||||
accountsConfig={accountsConfig}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default Locales
|
||||
192
packages/admin-ui/src/pages/Locales/helper.js
Normal file
192
packages/admin-ui/src/pages/Locales/helper.js
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
import * as R from 'ramda'
|
||||
import Autocomplete from 'src/components/inputs/formik/Autocomplete'
|
||||
import * as Yup from 'yup'
|
||||
|
||||
import { labels as timezoneList } from 'src/utils/timezone-list'
|
||||
|
||||
const getFields = (getData, names, onChange, auxElements = []) => {
|
||||
return R.filter(
|
||||
it => R.includes(it.name, names),
|
||||
allFields(getData, onChange, auxElements)
|
||||
)
|
||||
}
|
||||
|
||||
const allFields = (getData, onChange, auxElements = []) => {
|
||||
const getView = (data, code, compare) => it => {
|
||||
if (!data) return ''
|
||||
|
||||
return R.compose(
|
||||
it => `${R.prop(code)(it)} ${it?.isBeta ? '(Beta)' : ''}`,
|
||||
R.find(R.propEq(compare ?? 'code', it))
|
||||
)(data)
|
||||
}
|
||||
|
||||
const displayCodeArray = data => it => {
|
||||
if (!it) return it
|
||||
|
||||
return R.compose(R.join(', '), R.map(getView(data, 'code')))(it)
|
||||
}
|
||||
|
||||
const overriddenMachines = R.map(override => override.machine, auxElements)
|
||||
|
||||
const suggestionFilter = it =>
|
||||
R.differenceWith((x, y) => x.deviceId === y, it, overriddenMachines)
|
||||
|
||||
const machineData = getData(['machines'])
|
||||
const countryData = getData(['countries'])
|
||||
const currencyData = getData(['currencies'])
|
||||
const languageData = getData(['languages'])
|
||||
const rawCryptoData = getData(['cryptoCurrencies'])
|
||||
const cryptoData = rawCryptoData?.map(it => {
|
||||
it.codeLabel = `${it.code}${it.isBeta ? ' (Beta)' : ''}`
|
||||
return it
|
||||
})
|
||||
|
||||
const timezonesData = timezoneList
|
||||
|
||||
const findSuggestion = it => {
|
||||
const machine = R.find(R.propEq('deviceId', it.machine))(machineData)
|
||||
return machine ? [machine] : []
|
||||
}
|
||||
|
||||
return [
|
||||
{
|
||||
name: 'machine',
|
||||
width: 200,
|
||||
size: 'sm',
|
||||
view: getView(machineData, 'name', 'deviceId'),
|
||||
input: Autocomplete,
|
||||
inputProps: {
|
||||
options: it =>
|
||||
R.concat(findSuggestion(it))(suggestionFilter(machineData)),
|
||||
valueProp: 'deviceId',
|
||||
labelProp: 'name'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'country',
|
||||
width: 200,
|
||||
size: 'sm',
|
||||
view: getView(countryData, 'display'),
|
||||
input: Autocomplete,
|
||||
inputProps: {
|
||||
options: countryData,
|
||||
valueProp: 'code',
|
||||
labelProp: 'display'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'fiatCurrency',
|
||||
width: 150,
|
||||
size: 'sm',
|
||||
view: getView(currencyData, 'code'),
|
||||
input: Autocomplete,
|
||||
inputProps: {
|
||||
options: currencyData,
|
||||
valueProp: 'code',
|
||||
labelProp: 'code'
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'languages',
|
||||
width: 200,
|
||||
size: 'sm',
|
||||
view: displayCodeArray(languageData),
|
||||
input: Autocomplete,
|
||||
inputProps: {
|
||||
options: languageData,
|
||||
valueProp: 'code',
|
||||
labelProp: 'display',
|
||||
multiple: true
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'cryptoCurrencies',
|
||||
width: 170,
|
||||
size: 'sm',
|
||||
view: displayCodeArray(cryptoData),
|
||||
input: Autocomplete,
|
||||
inputProps: {
|
||||
options: cryptoData,
|
||||
valueProp: 'code',
|
||||
labelProp: 'codeLabel',
|
||||
multiple: true,
|
||||
optionsLimit: null,
|
||||
onChange
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'timezone',
|
||||
width: 320,
|
||||
size: 'sm',
|
||||
view: getView(timezonesData, 'label'),
|
||||
input: Autocomplete,
|
||||
inputProps: {
|
||||
options: timezonesData,
|
||||
valueProp: 'code',
|
||||
labelProp: 'label'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
const mainFields = (auxData, configureCoin) => {
|
||||
const getData = R.path(R.__, auxData)
|
||||
|
||||
return getFields(
|
||||
getData,
|
||||
['country', 'fiatCurrency', 'languages', 'cryptoCurrencies', 'timezone'],
|
||||
configureCoin,
|
||||
undefined
|
||||
)
|
||||
}
|
||||
|
||||
const overrides = (auxData, auxElements, configureCoin) => {
|
||||
const getData = R.path(R.__, auxData)
|
||||
|
||||
return getFields(
|
||||
getData,
|
||||
['machine', 'country', 'languages', 'cryptoCurrencies'],
|
||||
configureCoin,
|
||||
auxElements
|
||||
)
|
||||
}
|
||||
|
||||
const LocaleSchema = Yup.object().shape({
|
||||
country: Yup.string().label('Country').required(),
|
||||
fiatCurrency: Yup.string().label('Fiat currency').required(),
|
||||
languages: Yup.array().label('Languages').required().min(1).max(4),
|
||||
cryptoCurrencies: Yup.array().label('Crypto currencies').required().min(1),
|
||||
timezone: Yup.string().label('Timezone').required()
|
||||
})
|
||||
|
||||
const OverridesSchema = Yup.object().shape({
|
||||
machine: Yup.string().label('Machine').required(),
|
||||
country: Yup.string().label('Country').required(),
|
||||
languages: Yup.array().label('Languages').required().min(1).max(4),
|
||||
cryptoCurrencies: Yup.array().label('Crypto currencies').required().min(1)
|
||||
})
|
||||
|
||||
const localeDefaults = {
|
||||
country: '',
|
||||
fiatCurrency: '',
|
||||
languages: [],
|
||||
cryptoCurrencies: [],
|
||||
timezone: ''
|
||||
}
|
||||
|
||||
const overridesDefaults = {
|
||||
machine: '',
|
||||
country: '',
|
||||
languages: [],
|
||||
cryptoCurrencies: []
|
||||
}
|
||||
|
||||
export {
|
||||
mainFields,
|
||||
overrides,
|
||||
LocaleSchema,
|
||||
OverridesSchema,
|
||||
localeDefaults,
|
||||
overridesDefaults
|
||||
}
|
||||
3
packages/admin-ui/src/pages/Locales/index.js
Normal file
3
packages/admin-ui/src/pages/Locales/index.js
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
import Locales from './Locales'
|
||||
|
||||
export default Locales
|
||||
Loading…
Add table
Add a link
Reference in a new issue