mirror of
https://github.com/Qortal/Qortal-Hub.git
synced 2025-05-18 07:36:58 +00:00
Merge branch 'feature/multi-names' into feature/large-files-and-names
This commit is contained in:
commit
933c6622fb
File diff suppressed because it is too large
Load Diff
@ -66,6 +66,15 @@ export async function getNameInfo() {
|
||||
}
|
||||
}
|
||||
|
||||
export async function getAllUserNames() {
|
||||
const wallet = await getSaveWallet();
|
||||
const address = wallet.address0;
|
||||
const validApi = await getBaseApi();
|
||||
const response = await fetch(validApi + '/names/address/' + address);
|
||||
const nameData = await response.json();
|
||||
return nameData.map((item) => item.name);
|
||||
}
|
||||
|
||||
async function getKeyPair() {
|
||||
const res = await getData<any>('keyPair').catch(() => null);
|
||||
if (res) {
|
||||
@ -285,9 +294,10 @@ export const publishOnQDN = async ({
|
||||
tag4,
|
||||
tag5,
|
||||
uploadType = 'file',
|
||||
name,
|
||||
}) => {
|
||||
if (data && service) {
|
||||
const registeredName = await getNameInfo();
|
||||
const registeredName = name || (await getNameInfo());
|
||||
if (!registeredName) throw new Error('You need a name to publish');
|
||||
|
||||
const res = await publishData({
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { useContext, useEffect, useState } from 'react';
|
||||
import React, { useCallback, useContext, useEffect, useState } from 'react';
|
||||
import {
|
||||
AppCircle,
|
||||
AppCircleContainer,
|
||||
@ -72,7 +72,8 @@ const CustomMenuItem = styled(MenuItem)({
|
||||
// },
|
||||
});
|
||||
|
||||
export const AppPublish = ({ names, categories }) => {
|
||||
export const AppPublish = ({ categories, myAddress, myName }) => {
|
||||
const [names, setNames] = useState([]);
|
||||
const [name, setName] = useState('');
|
||||
const [title, setTitle] = useState('');
|
||||
const [description, setDescription] = useState('');
|
||||
@ -152,6 +153,25 @@ export const AppPublish = ({ names, categories }) => {
|
||||
getQapp(name, appType);
|
||||
}, [name, appType]);
|
||||
|
||||
const getNames = useCallback(async () => {
|
||||
if (!myAddress) return;
|
||||
try {
|
||||
setIsLoading('Loading names');
|
||||
const res = await fetch(
|
||||
`${getBaseApiReact()}/names/address/${myAddress}`
|
||||
);
|
||||
const data = await res.json();
|
||||
setNames(data?.map((item) => item.name));
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
} finally {
|
||||
setIsLoading('');
|
||||
}
|
||||
}, [myAddress]);
|
||||
useEffect(() => {
|
||||
getNames();
|
||||
}, [getNames]);
|
||||
|
||||
const publishApp = async () => {
|
||||
try {
|
||||
const data = {
|
||||
@ -195,6 +215,7 @@ export const AppPublish = ({ names, categories }) => {
|
||||
data: file,
|
||||
service: appType,
|
||||
title,
|
||||
name,
|
||||
description,
|
||||
category,
|
||||
tag1,
|
||||
|
@ -38,6 +38,7 @@ export const AppsDesktop = ({
|
||||
hasUnreadGroups,
|
||||
setDesktopViewMode,
|
||||
desktopViewMode,
|
||||
myAddress,
|
||||
}) => {
|
||||
const [availableQapps, setAvailableQapps] = useState([]);
|
||||
const [selectedAppInfo, setSelectedAppInfo] = useState(null);
|
||||
@ -458,6 +459,7 @@ export const AppsDesktop = ({
|
||||
setMode={setMode}
|
||||
myApp={myApp}
|
||||
myWebsite={myWebsite}
|
||||
myAddress={myAddress}
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
@ -485,7 +487,11 @@ export const AppsDesktop = ({
|
||||
myName={myName}
|
||||
/>
|
||||
{mode === 'publish' && !selectedTab && (
|
||||
<AppPublish names={myName ? [myName] : []} categories={categories} />
|
||||
<AppPublish
|
||||
names={myName ? [myName] : []}
|
||||
categories={categories}
|
||||
myAddress={myAddress}
|
||||
/>
|
||||
)}
|
||||
{tabs.map((tab) => {
|
||||
if (!iframeRefs.current[tab.tabId]) {
|
||||
@ -521,6 +527,7 @@ export const AppsDesktop = ({
|
||||
setMode={setMode}
|
||||
myApp={myApp}
|
||||
myWebsite={myWebsite}
|
||||
myAddress={myAddress}
|
||||
/>
|
||||
</Box>
|
||||
</>
|
||||
|
@ -23,6 +23,7 @@ export const AppsHomeDesktop = ({
|
||||
myWebsite,
|
||||
availableQapps,
|
||||
myName,
|
||||
myAddress,
|
||||
}) => {
|
||||
const [qortalUrl, setQortalUrl] = useState('');
|
||||
const theme = useTheme();
|
||||
@ -147,7 +148,7 @@ export const AppsHomeDesktop = ({
|
||||
</AppCircleContainer>
|
||||
</ButtonBase>
|
||||
|
||||
<AppsPrivate myName={myName} />
|
||||
<AppsPrivate myName={myName} myAddress={myAddress} />
|
||||
|
||||
<SortablePinnedApps
|
||||
isDesktop={true}
|
||||
|
@ -1,4 +1,10 @@
|
||||
import React, { useContext, useMemo, useState } from 'react';
|
||||
import React, {
|
||||
useCallback,
|
||||
useContext,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useState,
|
||||
} from 'react';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
@ -31,7 +37,7 @@ import {
|
||||
} from './Apps-styles';
|
||||
import AddIcon from '@mui/icons-material/Add';
|
||||
import ImageUploader from '../../common/ImageUploader';
|
||||
import { MyContext } from '../../App';
|
||||
import { getBaseApiReact, MyContext } from '../../App';
|
||||
import { fileToBase64 } from '../../utils/fileReading';
|
||||
import { objectToBase64 } from '../../qdn/encryption/group-encryption';
|
||||
import { getFee } from '../../background';
|
||||
@ -39,7 +45,10 @@ import { useAtom } from 'jotai';
|
||||
|
||||
const maxFileSize = 50 * 1024 * 1024; // 50MB
|
||||
|
||||
export const AppsPrivate = ({ myName }) => {
|
||||
export const AppsPrivate = ({ myName, myAddress }) => {
|
||||
const [names, setNames] = useState([]);
|
||||
const [name, setName] = useState(0);
|
||||
|
||||
const { openApp } = useHandlePrivateApps();
|
||||
const [file, setFile] = useState(null);
|
||||
const [logo, setLogo] = useState(null);
|
||||
@ -140,7 +149,7 @@ export const AppsPrivate = ({ myName }) => {
|
||||
try {
|
||||
if (selectedGroup === 0) return;
|
||||
if (!logo) throw new Error('Please select an image for a logo');
|
||||
if (!myName) throw new Error('You need a Qortal name to publish');
|
||||
if (!name) throw new Error('Please select a Qortal name');
|
||||
if (!newPrivateAppValues?.name) throw new Error('Your app needs a name');
|
||||
const base64Logo = await fileToBase64(logo);
|
||||
const base64App = await fileToBase64(file);
|
||||
@ -178,6 +187,7 @@ export const AppsPrivate = ({ myName }) => {
|
||||
identifier: newPrivateAppValues?.identifier,
|
||||
service: newPrivateAppValues?.service,
|
||||
uploadType: 'base64',
|
||||
name,
|
||||
})
|
||||
.then((response) => {
|
||||
if (!response?.error) {
|
||||
@ -195,7 +205,7 @@ export const AppsPrivate = ({ myName }) => {
|
||||
{
|
||||
identifier: newPrivateAppValues?.identifier,
|
||||
service: newPrivateAppValues?.service,
|
||||
name: myName,
|
||||
name,
|
||||
groupId: selectedGroup,
|
||||
},
|
||||
true
|
||||
@ -221,6 +231,22 @@ export const AppsPrivate = ({ myName }) => {
|
||||
};
|
||||
}
|
||||
|
||||
const getNames = useCallback(async () => {
|
||||
if (!myAddress) return;
|
||||
try {
|
||||
const res = await fetch(
|
||||
`${getBaseApiReact()}/names/address/${myAddress}`
|
||||
);
|
||||
const data = await res.json();
|
||||
setNames(data?.map((item) => item.name));
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}, [myAddress]);
|
||||
useEffect(() => {
|
||||
getNames();
|
||||
}, [getNames]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<ButtonBase
|
||||
@ -458,7 +484,34 @@ export const AppsPrivate = ({ myName }) => {
|
||||
<input {...getInputProps()} />
|
||||
{file ? 'Change' : 'Choose'} File
|
||||
</PublishQAppChoseFile>
|
||||
<Spacer height="20px" />
|
||||
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: '5px',
|
||||
}}
|
||||
>
|
||||
<Label>Select a Qortal name</Label>
|
||||
|
||||
<Select
|
||||
labelId="demo-simple-select-label"
|
||||
id="demo-simple-select"
|
||||
value={name}
|
||||
label="Groups where you are an admin"
|
||||
onChange={(e) => setName(e.target.value)}
|
||||
>
|
||||
<MenuItem value={0}>No name selected</MenuItem>
|
||||
{names.map((name) => {
|
||||
return (
|
||||
<MenuItem key={name} value={name}>
|
||||
{name}
|
||||
</MenuItem>
|
||||
);
|
||||
})}
|
||||
</Select>
|
||||
</Box>
|
||||
<Spacer height="20px" />
|
||||
|
||||
<Box
|
||||
|
@ -519,7 +519,7 @@ export const Group = ({
|
||||
});
|
||||
});
|
||||
} catch (error) {
|
||||
console.log('error', error);
|
||||
console.error(error);
|
||||
}
|
||||
}, [setMutedGroups]);
|
||||
|
||||
@ -2317,6 +2317,7 @@ export const Group = ({
|
||||
hasUnreadDirects={directChatHasUnread}
|
||||
show={desktopViewMode === 'apps'}
|
||||
myName={userInfo?.name}
|
||||
myAddress={userInfo?.address}
|
||||
isGroups={isOpenSideViewGroups}
|
||||
isDirects={isOpenSideViewDirects}
|
||||
hasUnreadGroups={groupChatHasUnread || groupsAnnHasUnread}
|
||||
|
@ -39,6 +39,7 @@ import {
|
||||
transferAsset,
|
||||
} from '../background';
|
||||
import {
|
||||
getAllUserNames,
|
||||
getNameInfo,
|
||||
uint8ArrayToObject,
|
||||
} from '../backgroundFunctions/encryption';
|
||||
@ -1065,7 +1066,8 @@ export const publishQDNResource = async (
|
||||
if (appFee && appFee > 0 && appFeeRecipient) {
|
||||
hasAppFee = true;
|
||||
}
|
||||
const registeredName = await getNameInfo();
|
||||
|
||||
const registeredName = data?.name || (await getNameInfo());
|
||||
const name = registeredName;
|
||||
if (!name) {
|
||||
throw new Error('User has no Qortal name');
|
||||
@ -1145,6 +1147,7 @@ export const publishQDNResource = async (
|
||||
text1: 'Do you give this application permission to publish to QDN?',
|
||||
text2: `service: ${service}`,
|
||||
text3: `identifier: ${identifier || null}`,
|
||||
text4: `name: ${registeredName}`,
|
||||
fee: fee.fee,
|
||||
...handleDynamicValues,
|
||||
},
|
||||
@ -1265,10 +1268,19 @@ export const publishMultipleQDNResources = async (
|
||||
|
||||
const fee = await getFee('ARBITRARY');
|
||||
const registeredName = await getNameInfo();
|
||||
|
||||
const name = registeredName;
|
||||
if (!name) {
|
||||
throw new Error('You need a Qortal name to publish.');
|
||||
}
|
||||
const userNames = await getAllUserNames();
|
||||
data.resources?.forEach((item) => {
|
||||
if (item?.name && !userNames?.includes(item.name))
|
||||
throw new Error(
|
||||
`The name ${item.name}, does not belong to the publisher.`
|
||||
);
|
||||
});
|
||||
|
||||
const appFee = data?.appFee ? +data.appFee : undefined;
|
||||
const appFeeRecipient = data?.appFeeRecipient;
|
||||
let hasAppFee = false;
|
||||
@ -1336,7 +1348,7 @@ export const publishMultipleQDNResources = async (
|
||||
<div class="resource-detail"><span>Service:</span> ${
|
||||
resource.service
|
||||
}</div>
|
||||
<div class="resource-detail"><span>Name:</span> ${name}</div>
|
||||
<div class="resource-detail"><span>Name:</span> ${resource?.name || name}</div>
|
||||
<div class="resource-detail"><span>Identifier:</span> ${
|
||||
resource.identifier
|
||||
}</div>
|
||||
@ -1377,6 +1389,7 @@ export const publishMultipleQDNResources = async (
|
||||
reason: errorMsg,
|
||||
identifier: resource.identifier,
|
||||
service: resource.service,
|
||||
name: resource?.name || name,
|
||||
});
|
||||
continue;
|
||||
}
|
||||
@ -1386,6 +1399,7 @@ export const publishMultipleQDNResources = async (
|
||||
reason: errorMsg,
|
||||
identifier: resource.identifier,
|
||||
service: resource.service,
|
||||
name: resource?.name || name,
|
||||
});
|
||||
continue;
|
||||
}
|
||||
@ -1415,6 +1429,7 @@ export const publishMultipleQDNResources = async (
|
||||
reason: errorMsg,
|
||||
identifier: resource.identifier,
|
||||
service: resource.service,
|
||||
name: resource?.name || name,
|
||||
});
|
||||
continue;
|
||||
}
|
||||
@ -1448,6 +1463,7 @@ export const publishMultipleQDNResources = async (
|
||||
reason: errorMsg,
|
||||
identifier: resource.identifier,
|
||||
service: resource.service,
|
||||
name: resource?.name || name,
|
||||
});
|
||||
continue;
|
||||
}
|
||||
@ -1463,8 +1479,8 @@ export const publishMultipleQDNResources = async (
|
||||
publishData,
|
||||
[
|
||||
{
|
||||
registeredName: encodeURIComponent(name),
|
||||
data: rawData,
|
||||
registeredName: encodeURIComponent(resource?.name || name),
|
||||
service: service,
|
||||
identifier: encodeURIComponent(identifier),
|
||||
uploadType: dataType,
|
||||
@ -1495,6 +1511,7 @@ export const publishMultipleQDNResources = async (
|
||||
reason: errorMsg,
|
||||
identifier: resource.identifier,
|
||||
service: resource.service,
|
||||
name: resource?.name || name,
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
@ -1502,6 +1519,7 @@ export const publishMultipleQDNResources = async (
|
||||
reason: error?.message || 'Unknown error',
|
||||
identifier: resource.identifier,
|
||||
service: resource.service,
|
||||
name: resource?.name || name,
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -4311,9 +4329,10 @@ export const updateNameRequest = async (data, isFromExtension) => {
|
||||
const fee = await getFee('UPDATE_NAME');
|
||||
const resPermission = await getUserPermission(
|
||||
{
|
||||
text1: `Do you give this application permission to register this name?`,
|
||||
highlightedText: data.newName,
|
||||
text2: data?.description,
|
||||
text1: `Do you give this application permission to update this name?`,
|
||||
text2: `previous name: ${oldName}`,
|
||||
text3: `new name: ${newName}`,
|
||||
text4: data?.description,
|
||||
fee: fee.fee,
|
||||
},
|
||||
isFromExtension
|
||||
@ -4747,7 +4766,7 @@ export const createGroupRequest = async (data, isFromExtension) => {
|
||||
];
|
||||
const missingFields: string[] = [];
|
||||
requiredFields.forEach((field) => {
|
||||
if (data[field] !== undefined && data[field] !== null) {
|
||||
if (data[field] === undefined || data[field] === null) {
|
||||
missingFields.push(field);
|
||||
}
|
||||
});
|
||||
@ -4799,7 +4818,7 @@ export const updateGroupRequest = async (data, isFromExtension) => {
|
||||
];
|
||||
const missingFields: string[] = [];
|
||||
requiredFields.forEach((field) => {
|
||||
if (data[field] !== undefined && data[field] !== null) {
|
||||
if (data[field] === undefined || data[field] === null) {
|
||||
missingFields.push(field);
|
||||
}
|
||||
});
|
||||
@ -4934,7 +4953,7 @@ export const sellNameRequest = async (data, isFromExtension) => {
|
||||
const requiredFields = ['salePrice', 'nameForSale'];
|
||||
const missingFields: string[] = [];
|
||||
requiredFields.forEach((field) => {
|
||||
if (data[field] !== undefined && data[field] !== null) {
|
||||
if (data[field] === undefined || data[field] === null) {
|
||||
missingFields.push(field);
|
||||
}
|
||||
});
|
||||
@ -4978,7 +4997,7 @@ export const cancelSellNameRequest = async (data, isFromExtension) => {
|
||||
const requiredFields = ['nameForSale'];
|
||||
const missingFields: string[] = [];
|
||||
requiredFields.forEach((field) => {
|
||||
if (data[field] !== undefined && data[field] !== null) {
|
||||
if (data[field] === undefined || data[field] === null) {
|
||||
missingFields.push(field);
|
||||
}
|
||||
});
|
||||
@ -5018,7 +5037,7 @@ export const buyNameRequest = async (data, isFromExtension) => {
|
||||
const requiredFields = ['nameForSale'];
|
||||
const missingFields: string[] = [];
|
||||
requiredFields.forEach((field) => {
|
||||
if (data[field] !== undefined && data[field] !== null) {
|
||||
if (data[field] === undefined || data[field] === null) {
|
||||
missingFields.push(field);
|
||||
}
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user