diff --git a/src/App.tsx b/src/App.tsx index 8a36a7d..4ab0d28 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1028,12 +1028,7 @@ function App() { const logoutFunc = useCallback(async () => { try { - if (hasSettingsChanged) { - await showUnsavedChanges({ - message: - 'Your settings have changed. If you logout you will lose your changes. Click on the save button in the header to keep your changed settings.', - }); // TODO translate - } else if (extState === 'authenticated') { + if (extState === 'authenticated') { await showUnsavedChanges({ message: 'Are you sure you would like to logout?', }); @@ -3014,13 +3009,16 @@ function App() { })} - { returnToMain(); }} > - {t('core:action.continue', { postProcess: 'capitalize' })} - + + {t('core:action.continue', { postProcess: 'capitalize' })} + + )} {extState === 'transfer-success-request' && ( @@ -3221,7 +3219,7 @@ function App() { onClick={onOkUnsavedChanges} autoFocus > - {t('core:action.decline', { + {t('core:action.continue_logout', { postProcess: 'capitalize', })} @@ -3270,6 +3268,8 @@ function App() { lineHeight: 1.2, maxWidth: '90%', textAlign: 'center', + fontSize: '16px', + marginBottom: '10px', }} > {messageQortalRequestExtension?.text1} @@ -3316,8 +3316,8 @@ function App() { > {messageQortalRequestExtension?.text3} - + )} @@ -3342,11 +3342,15 @@ function App() { )} {messageQortalRequestExtension?.html && ( -
+ <> + + +
+ )} diff --git a/src/background.ts b/src/background.ts index dca7e62..b34a01b 100644 --- a/src/background.ts +++ b/src/background.ts @@ -3689,7 +3689,7 @@ export const checkThreads = async (bringBack) => { dataToBringBack.push(thread); } } catch (error) { - conosle.log({ error }); + console.log({ error }); } } diff --git a/src/components/Apps/AppsDesktop.tsx b/src/components/Apps/AppsDesktop.tsx index b5a5cba..80f57b9 100644 --- a/src/components/Apps/AppsDesktop.tsx +++ b/src/components/Apps/AppsDesktop.tsx @@ -414,8 +414,23 @@ export const AppsDesktop = ({ setDesktopViewMode('dev'); }} > - - + + )} diff --git a/src/components/Apps/AppsDevModeNavBar.tsx b/src/components/Apps/AppsDevModeNavBar.tsx index 1c0422a..1bfcf42 100644 --- a/src/components/Apps/AppsDevModeNavBar.tsx +++ b/src/components/Apps/AppsDevModeNavBar.tsx @@ -180,7 +180,7 @@ export const AppsDevModeNavBar = () => { > { }, ...prev, ]); + setName(''); + setDescription(''); + setGroupType('1'); res(response); return; } @@ -430,12 +433,12 @@ export const AddGroup = ({ address, open, setOpen }) => { onChange={handleChangeApprovalThreshold} > - {t('core.count.none', { + {t('core:count.none', { postProcess: 'capitalize', })} - {t('core.count.one', { + {t('core:count.one', { postProcess: 'capitalize', })} @@ -454,7 +457,7 @@ export const AddGroup = ({ address, open, setOpen }) => { }} > @@ -466,40 +469,40 @@ export const AddGroup = ({ address, open, setOpen }) => { onChange={handleChangeMinBlock} > - {t('core.time.minute', { count: 5 })} + {t('core:time.minute', { count: 5 })} - {t('core.time.minute', { count: 10 })} + {t('core:time.minute', { count: 10 })} - {t('core.time.minute', { count: 30 })} + {t('core:time.minute', { count: 30 })} - {t('core.time.hour', { count: 1 })} + {t('core:time.hour', { count: 1 })} - {t('core.time.hour', { count: 3 })} + {t('core:time.hour', { count: 3 })} - {t('core.time.hour', { count: 5 })} + {t('core:time.hour', { count: 5 })} - {t('core.time.hour', { count: 7 })} + {t('core:time.hour', { count: 7 })} - {t('core.time.hour', { count: 12 })} + {t('core:time.hour', { count: 12 })} - {t('core.time.day', { count: 1 })} + {t('core:time.day', { count: 1 })} - {t('core.time.day', { count: 3 })} + {t('core:time.day', { count: 3 })} - {t('core.time.day', { count: 5 })} + {t('core:time.day', { count: 5 })} - {t('core.time.day', { count: 7 })} + {t('core:time.day', { count: 7 })} @@ -511,7 +514,7 @@ export const AddGroup = ({ address, open, setOpen }) => { }} > @@ -523,37 +526,37 @@ export const AddGroup = ({ address, open, setOpen }) => { onChange={handleChangeMaxBlock} > - {t('core.time.hour', { count: 1 })} + {t('core:time.hour', { count: 1 })} - 3{t('core.time.hour', { count: 3 })} + 3{t('core:time.hour', { count: 3 })} - {t('core.time.hour', { count: 5 })} + {t('core:time.hour', { count: 5 })} - {t('core.time.hour', { count: 7 })} + {t('core:time.hour', { count: 7 })} - {t('core.time.hour', { count: 12 })} + {t('core:time.hour', { count: 12 })} - {t('core.time.day', { count: 1 })} + {t('core:time.day', { count: 1 })} - {t('core.time.day', { count: 3 })} + {t('core:time.day', { count: 3 })} - {t('core.time.day', { count: 5 })} + {t('core:time.day', { count: 5 })} - {t('core.time.day', { count: 7 })} + {t('core:time.day', { count: 7 })} - {t('core.time.day', { count: 10 })} + {t('core:time.day', { count: 10 })} - {t('core.time.day', { count: 15 })} + {t('core:time.day', { count: 15 })} @@ -570,7 +573,7 @@ export const AddGroup = ({ address, open, setOpen }) => { color="primary" onClick={handleCreateGroup} > - {t('group.action.create', { + {t('group:action.create_group', { postProcess: 'capitalize', })} diff --git a/src/components/Group/InviteMember.tsx b/src/components/Group/InviteMember.tsx index db01b59..fe1fdb3 100644 --- a/src/components/Group/InviteMember.tsx +++ b/src/components/Group/InviteMember.tsx @@ -97,16 +97,16 @@ export const InviteMember = ({ groupId, setInfoSnack, setOpenSnack, show }) => { label={t('group:invitation_expiry', { postProcess: 'capitalize' })} onChange={handleChange} > - {t('core.time.hour', { count: 3 })} - {t('core.time.hour', { count: 6 })} - {t('core.time.hour', { count: 12 })} - {t('core.time.day', { count: 1 })} - {t('core.time.day', { count: 3 })} - {t('core.time.day', { count: 5 })} - {t('core.time.day', { count: 7 })} - {t('core.time.day', { count: 10 })} - {t('core.time.day', { count: 15 })} - {t('core.time.day', { count: 30 })} + {t('core:time.hour', { count: 3 })} + {t('core:time.hour', { count: 6 })} + {t('core:time.hour', { count: 12 })} + {t('core:time.day', { count: 1 })} + {t('core:time.day', { count: 3 })} + {t('core:time.day', { count: 5 })} + {t('core:time.day', { count: 7 })} + {t('core:time.day', { count: 10 })} + {t('core:time.day', { count: 15 })} + {t('core:time.day', { count: 30 })} { value={paymentPassword} onChange={(e) => setPaymentPassword(e.target.value)} autoComplete="off" + onKeyDown={(e) => { + if (e.key === 'Enter') { + if (isLoadingSendCoin) return; + sendCoinFunc(); + } + }} /> diff --git a/src/components/ReactionPicker.tsx b/src/components/ReactionPicker.tsx index c95adcf..911a396 100644 --- a/src/components/ReactionPicker.tsx +++ b/src/components/ReactionPicker.tsx @@ -27,15 +27,25 @@ export const ReactionPicker = ({ onReaction }) => { if (showPicker) { setShowPicker(false); } else { - // Get the button's position const buttonRect = buttonRef.current.getBoundingClientRect(); const pickerWidth = 350; + const pickerHeight = 400; // Match Picker height prop - // Calculate position to align the right edge of the picker with the button's right edge - setPickerPosition({ - top: buttonRect.bottom + window.scrollY, // Position below the button - left: buttonRect.right + window.scrollX - pickerWidth, // Align right edges - }); + // Initial position (below the button) + let top = buttonRect.bottom + window.scrollY; + let left = buttonRect.right + window.scrollX - pickerWidth; + + // If picker would overflow bottom, show it above the button + const overflowBottom = + top + pickerHeight > window.innerHeight + window.scrollY; + if (overflowBottom) { + top = buttonRect.top + window.scrollY - pickerHeight; + } + + // Optional: prevent overflow on the left too + if (left < 0) left = 0; + + setPickerPosition({ top, left }); setShowPicker(true); } }; @@ -92,12 +102,13 @@ export const ReactionPicker = ({ onReaction }) => { allowExpandReactions={true} autoFocusSearch={false} emojiStyle={EmojiStyle.NATIVE} - height="450" + height={400} onEmojiClick={handlePicker} onReactionClick={handleReaction} - reactionsDefaultOpen={true} + // reactionsDefaultOpen={true} + // open={true} theme={Theme.DARK} - width="350" + width={350} />
, document.body diff --git a/src/components/Theme/ThemeContext.tsx b/src/components/Theme/ThemeContext.tsx index 72d4f3b..3ebace0 100644 --- a/src/components/Theme/ThemeContext.tsx +++ b/src/components/Theme/ThemeContext.tsx @@ -25,7 +25,7 @@ const ThemeContext = createContext({ toggleTheme: () => {}, userThemes: [defaultTheme], addUserTheme: (themes) => {}, - setUserTheme: (theme) => {}, + setUserTheme: (theme, themes) => {}, currentThemeId: 'default', }); @@ -83,13 +83,13 @@ export const ThemeProvider = ({ children }) => { saveSettings(themes); }; - const setUserTheme = (theme) => { + const setUserTheme = (theme, themes) => { if (theme.id === 'default') { setCurrentThemeId('default'); - saveSettings(userThemes, themeMode, 'default'); + saveSettings(themes || userThemes, themeMode, 'default'); } else { setCurrentThemeId(theme.id); - saveSettings(userThemes, themeMode, theme.id); + saveSettings(themes || userThemes, themeMode, theme.id); } }; diff --git a/src/components/Theme/ThemeManager.tsx b/src/components/Theme/ThemeManager.tsx index eca0e9f..badcb42 100644 --- a/src/components/Theme/ThemeManager.tsx +++ b/src/components/Theme/ThemeManager.tsx @@ -119,7 +119,7 @@ export default function ThemeManager() { const newTheme = { ...themeDraft, id: uid.rnd() }; const updatedThemes = [...userThemes, newTheme]; addUserTheme(updatedThemes); - setUserTheme(newTheme); + setUserTheme(newTheme, updatedThemes); } setOpenEditor(false); }; @@ -135,19 +135,22 @@ export default function ThemeManager() { ); if (defaultTheme) { - setUserTheme(defaultTheme); + setUserTheme(defaultTheme, updatedThemes); } else { // Emergency fallback - setUserTheme({ - light: lightThemeOptions, - dark: darkThemeOptions, - }); + setUserTheme( + { + light: lightThemeOptions, + dark: darkThemeOptions, + }, + updatedThemes + ); } } }; const handleApplyTheme = (theme) => { - setUserTheme(theme); + setUserTheme(theme, null); }; const handleColorChange = (mode, fieldPath, color) => { @@ -210,7 +213,8 @@ export default function ThemeManager() { const newTheme = { ...importedTheme, id: uid.rnd() }; const updatedThemes = [...userThemes, newTheme]; addUserTheme(updatedThemes); - setUserTheme(newTheme); + + setUserTheme(newTheme, updatedThemes); } catch (error) { console.error(error); } diff --git a/src/qortalRequests.ts b/src/qortalRequests.ts index a3bfd8b..2466d3d 100644 --- a/src/qortalRequests.ts +++ b/src/qortalRequests.ts @@ -61,6 +61,7 @@ import { buyNameRequest, sellNameRequest, cancelSellNameRequest, + signForeignFees, multiPaymentWithPrivateData, transferAssetRequest, } from './qortalRequests/get'; @@ -754,7 +755,7 @@ function setupMessageListenerQortalRequest() { case 'UPDATE_FOREIGN_FEE': { try { - const res = await updateForeignFee(request.payload); + const res = await updateForeignFee(request.payload, isFromExtension); event.source.postMessage( { requestId: request.requestId, @@ -806,7 +807,10 @@ function setupMessageListenerQortalRequest() { case 'SET_CURRENT_FOREIGN_SERVER': { try { - const res = await setCurrentForeignServer(request.payload); + const res = await setCurrentForeignServer( + request.payload, + isFromExtension + ); event.source.postMessage( { requestId: request.requestId, @@ -832,7 +836,7 @@ function setupMessageListenerQortalRequest() { case 'ADD_FOREIGN_SERVER': { try { - const res = await addForeignServer(request.payload); + const res = await addForeignServer(request.payload, isFromExtension); event.source.postMessage( { requestId: request.requestId, @@ -858,7 +862,10 @@ function setupMessageListenerQortalRequest() { case 'REMOVE_FOREIGN_SERVER': { try { - const res = await removeForeignServer(request.payload); + const res = await removeForeignServer( + request.payload, + isFromExtension + ); event.source.postMessage( { requestId: request.requestId, @@ -1892,6 +1899,32 @@ function setupMessageListenerQortalRequest() { } break; } + case 'SIGN_FOREIGN_FEES': { + try { + const res = await signForeignFees(request.payload, isFromExtension); + event.source.postMessage( + { + requestId: request.requestId, + action: request.action, + payload: res, + type: 'backgroundMessageResponse', + }, + event.origin + ); + } catch (error) { + event.source.postMessage( + { + requestId: request.requestId, + action: request.action, + error: error.message, + type: 'backgroundMessageResponse', + }, + event.origin + ); + } + break; + } + default: break; } diff --git a/src/qortalRequests/get.ts b/src/qortalRequests/get.ts index 7b971f6..d4ce1bf 100644 --- a/src/qortalRequests/get.ts +++ b/src/qortalRequests/get.ts @@ -1302,10 +1302,7 @@ export const publishMultipleQDNResources = async ( html: `
+ +
+
Total Unlocking Fee:
+
${(+buyingFees?.unlock?.fee * atAddresses?.length)?.toFixed(8)} ${buyingFees.ticker}
+
+ This fee is an estimate based on ${atAddresses?.length} ${atAddresses?.length > 1 ? 'orders' : 'order'}, assuming a 300-byte size at a rate of ${buyingFees?.unlock?.feePerKb?.toFixed(8)} ${buyingFees.ticker} per KB. +
+ +
Total Locking Fee:
+
${+buyingFees?.lock.fee.toFixed(8)} ${buyingFees.ticker} per kb
+ +
+
+`, }, isFromExtension ); @@ -4934,6 +5053,70 @@ export const buyNameRequest = async (data, isFromExtension) => { } }; +export const signForeignFees = async (data, isFromExtension) => { + const resPermission = await getUserPermission( + { + text1: `Do you give this application permission to sign the required fees for all your trade offers?`, + }, + isFromExtension + ); + const { accepted } = resPermission; + if (accepted) { + const wallet = await getSaveWallet(); + const address = wallet.address0; + const resKeyPair = await getKeyPair(); + const parsedData = resKeyPair; + const uint8PrivateKey = Base58.decode(parsedData.privateKey); + const uint8PublicKey = Base58.decode(parsedData.publicKey); + const keyPair = { + privateKey: uint8PrivateKey, + publicKey: uint8PublicKey, + }; + + const unsignedFeesUrl = await createEndpoint( + `/crosschain/unsignedfees/${address}` + ); + + const unsignedFeesResponse = await fetch(unsignedFeesUrl); + + const unsignedFees = await unsignedFeesResponse.json(); + + const signedFees = []; + + unsignedFees.forEach((unsignedFee) => { + const unsignedDataDecoded = Base58.decode(unsignedFee.data); + + const signature = nacl.sign.detached( + unsignedDataDecoded, + keyPair.privateKey + ); + + const signedFee = { + timestamp: unsignedFee.timestamp, + data: `${Base58.encode(signature)}`, + atAddress: unsignedFee.atAddress, + fee: unsignedFee.fee, + }; + + signedFees.push(signedFee); + }); + + const signedFeesUrl = await createEndpoint(`/crosschain/signedfees`); + + await fetch(signedFeesUrl, { + method: 'POST', + headers: { + Accept: '*/*', + 'Content-Type': 'application/json', + }, + body: `${JSON.stringify(signedFees)}`, + }); + + return true; + } else { + throw new Error('User declined request'); + } +}; export const multiPaymentWithPrivateData = async (data, isFromExtension) => { const requiredFields = ['payments', 'assetId']; requiredFields.forEach((field) => { @@ -5075,19 +5258,15 @@ export const multiPaymentWithPrivateData = async (data, isFromExtension) => { html: `