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 }) => {
}}
>
- {t('group.block_delay.minimum', {
+ {t('group:block_delay.minimum', {
postProcess: 'capitalize',
})}
@@ -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 }) => {
}}
>
- {t('group.block_delay.maximum', {
+ {t('group:block_delay.maximum', {
postProcess: 'capitalize',
})}
@@ -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: `