Skip to content

Commit

Permalink
QA Feedback (#21)
Browse files Browse the repository at this point in the history
  • Loading branch information
nhenin committed Nov 1, 2023
1 parent c7ec613 commit 72c7e12
Show file tree
Hide file tree
Showing 5 changed files with 118 additions and 81 deletions.
2 changes: 1 addition & 1 deletion src/components/Connection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ export const ConnectedWallet : React.FC<ConnectedProps> = ({ runtimeURL,selecte
<span style={{fontSize: "medium"}}>
<Image src={selectedWalletExtension.icon} className="walletIcon" alt="" />
&nbsp;&nbsp;&nbsp;
{(adas).toString()}.
{(adas).toLocaleString()}.
</span>
<span style={{fontSize: "smaller"}}>{decimalADAs + ' '} </span>
<span style={{fontWeight: 'bold',fontSize: "small"}}> {isMainnet ? ' ₳' : ' t₳' }</span>
Expand Down
31 changes: 28 additions & 3 deletions src/components/modals/NewVesting.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ type FormData = {
claimerAddress: string;
};



const initialFormData : () => FormData = () => ({
firstName: '',
lastName: '',
Expand All @@ -36,7 +38,7 @@ const initialFormData : () => FormData = () => ({
claimerAddress: '',
})

const formErrorsInitialState = {
const formErrorsInitialState : FormDataError = {
firstName: null,
lastName: null,
title: null,
Expand All @@ -45,14 +47,23 @@ const formErrorsInitialState = {
claimerAddress: null,
}

type FormDataError = {
firstName: string | null;
lastName : string | null;
title : string | null;
initialDepositAmount: string | null;
startDate: string | null;
claimerAddress: string| null;
};

const NewVestingScheduleModal: React.FC<NewVestingScheduleModalProps> = ({ showModal, closeModal, handleCreateVestingContract, changeAddress}) => {


let [loading, setLoading] = useState(false);

const [formData, setFormData] = useState<FormData>(initialFormData());

const [formErrors, setFormErrors] = useState(formErrorsInitialState);
const [formErrors, setFormErrors] = useState<FormDataError>(formErrorsInitialState);

const handleInputChange = (e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement>) => {
const { id, value } = e.target;
Expand All @@ -79,6 +90,15 @@ const NewVestingScheduleModal: React.FC<NewVestingScheduleModalProps> = ({ showM
errors = { ...errors, [key]: 'This field is required' };
}
}
if (lengthInUtf8Bytes(formData.firstName) >= 64){
errors = { ...errors, "firstName": 'This field is too long to be stored on chain( 64 bytes maximum)' };
}
if (lengthInUtf8Bytes(formData.lastName) >= 64){
errors = { ...errors, "lastName": 'This field is too long to be stored on chain( 64 bytes maximum)' };
}
if (lengthInUtf8Bytes(formData.title) >= 64){
errors = { ...errors, "title": 'This field is too long to be stored on chain( 64 bytes maximum)' };
}

setFormErrors(errors);

Expand Down Expand Up @@ -111,6 +131,11 @@ const NewVestingScheduleModal: React.FC<NewVestingScheduleModalProps> = ({ showM
closeModal();
}

function lengthInUtf8Bytes(str : string) {
// Matches only the 10.. bytes that are non-initial characters in a multi-byte sequence.
var m = encodeURIComponent(str).match(/%[89ABab]/g);
return str.length + (m ? m.length : 0);
}

return (
<>
Expand Down Expand Up @@ -153,7 +178,7 @@ const NewVestingScheduleModal: React.FC<NewVestingScheduleModalProps> = ({ showM
<div className="form-group my-2 col-6">
<label htmlFor="initialDepositAmount">Initial Deposit (in ₳)</label>
<input
type="text"
type="number"
className="form-control"
id="initialDepositAmount"
value={formData.initialDepositAmount}
Expand Down
64 changes: 27 additions & 37 deletions src/components/vesting/Claimer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,16 @@ import { useNavigate } from 'react-router-dom';
import { BrowserRuntimeLifecycleOptions, mkRuntimeLifecycle } from "@marlowe.io/runtime-lifecycle/browser";
import { Vesting } from "@marlowe.io/language-examples";
import { mkRestClient } from "@marlowe.io/runtime-rest-client";
import { AddressBech32, ContractId, Tags, addressBech32, unAddressBech32 } from '@marlowe.io/runtime-core';
import { SupportedWallet } from '@marlowe.io/wallet/browser';
import { AddressBech32, ContractId, Tags, unAddressBech32, unContractId } from '@marlowe.io/runtime-core';
import { RuntimeLifecycle } from '@marlowe.io/runtime-lifecycle/api';
import { ContractDetails } from '@marlowe.io/runtime-rest-client/contract/details';
import HashLoader from 'react-spinners/HashLoader';
import { Input } from '@marlowe.io/language-core-v1';
import { Contract } from './Models';
import { contractIdLink, displayCloseCondition } from './Utils';
import { contractIdLink, cssOverrideSpinnerCentered, displayCloseCondition, formatADAs } from './Utils';
import { ConnectionWallet } from '../Connection';
import { Footer } from '../Footer';
import { SupportedWalletName } from '@marlowe.io/wallet/browser';


type YourTokenPlansProps = {
Expand Down Expand Up @@ -47,13 +47,20 @@ const YourTokenPlans: React.FC<YourTokenPlansProps> = ({runtimeURL,marloweScanUR
const fetchData = async () => {
if(isFetching) return;
try {
const runtimeLifecycleParameters : BrowserRuntimeLifecycleOptions = { runtimeURL:runtimeURL, walletName:selectedAWalletExtension as SupportedWallet}
const runtimeLifecycleParameters : BrowserRuntimeLifecycleOptions = { runtimeURL:runtimeURL, walletName:selectedAWalletExtension as SupportedWalletName}
const runtimeLifecycle = await mkRuntimeLifecycle(runtimeLifecycleParameters).then((a) => {setRuntimeLifecycle(a);return a})
const restClient = mkRestClient(runtimeURL);
const changeAddress = await runtimeLifecycle.wallet.getChangeAddress()
.then((changeAddress : AddressBech32) => {setChangeAddress(unAddressBech32(changeAddress));return changeAddress;})

const contractIdsAndTags : [ContractId,Tags][] = (await restClient.getContracts({ partyAddresses:[changeAddress],tags: [dAppId] })).headers.map((header) => [header.contractId,header.tags]);
const contractsClosedIds = contractsClosed.map(c => unContractId(c.contractId))
const contractIdsAndTags : [ContractId,Tags][] =
(await restClient.getContracts({ partyAddresses:[changeAddress],tags: [dAppId] }))
.headers
.filter((header) => !contractsClosedIds.includes(unContractId(header.contractId)))
.filter(header => header.tags[dAppId].claimerId === (unAddressBech32(changeAddress).slice(0,18)))
.map((header) => [header.contractId,header.tags]);

const contractIdsAndDetails : [ContractId,Tags,ContractDetails] []= await Promise.all(
contractIdsAndTags.map(([contractId,tags]) =>
restClient
Expand Down Expand Up @@ -97,7 +104,8 @@ const YourTokenPlans: React.FC<YourTokenPlansProps> = ({runtimeURL,marloweScanUR
isSelfAttributed : tags[dAppId].isSelfAttributed === 1,
providerId : tags[dAppId].providerId,
claimer : {firstName : tags[dAppId].firstName, lastName:tags[dAppId].lastName, id: tags[dAppId].claimerId },
state : state}))))).filter(contract => contract.claimer.id === (unAddressBech32(changeAddress).slice(0,18)))
state : state})))))


setContractsWithinVestingPeriod
(allContracts
Expand All @@ -107,10 +115,15 @@ const YourTokenPlans: React.FC<YourTokenPlansProps> = ({runtimeURL,marloweScanUR
(allContracts
.filter(c => c.state.name === "VestingEnded")
.map (c => c as Contract<Vesting.VestingEnded>))
setContractsClosed
(allContracts
.filter(c => c.state.name === "Closed")
.map (c => c as Contract<Vesting.Closed>))

const newContractsClosed = allContracts
.filter(c => c.state.name === "Closed")
.map (c => c as Contract<Vesting.Closed>)

if(newContractsClosed.length > 0 ) {
setContractsClosed(contractsClosed.concat(newContractsClosed))
}

setIsFetchingFirstTime(false)
setIsFetching(false)
} catch (err : any) {
Expand All @@ -125,7 +138,7 @@ const YourTokenPlans: React.FC<YourTokenPlansProps> = ({runtimeURL,marloweScanUR
// Clear the interval when the component is unmounted
return () => clearInterval(intervalId);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [selectedAWalletExtension, navigate]);
}, [selectedAWalletExtension, contractsClosed,navigate]);



Expand Down Expand Up @@ -212,7 +225,7 @@ const YourTokenPlans: React.FC<YourTokenPlansProps> = ({runtimeURL,marloweScanUR
<td> <span className='text-primary'>Plan Ended</span></td>
<td>{contract.state.scheme.frequency}</td>
<td>{contract.state.scheme.numberOfPeriods.toString()}</td>
<td>{formatADAs(contract.state.quantities.total)}</td>
<td><span style={{whiteSpace:'nowrap'}}>{formatADAs(contract.state.quantities.total)}</span></td>
<td>{((contract.state.quantities.withdrawable* 100n) / contract.state.quantities.total) + '%'}</td>
<td>
{contract.state.withdrawInput?
Expand Down Expand Up @@ -248,7 +261,7 @@ const YourTokenPlans: React.FC<YourTokenPlansProps> = ({runtimeURL,marloweScanUR
}</td>
<td>{contract.state.scheme.frequency}</td>
<td>{contract.state.scheme.numberOfPeriods.toString()}</td>
<td>{formatADAs(contract.state.quantities.total)}</td>
<td><span style={{whiteSpace:'nowrap'}}>{formatADAs(contract.state.quantities.total)}</span></td>
<td>{(((contract.state.quantities.vested - contract.state.quantities.claimed) * 100n) / contract.state.quantities.total) + '%'}</td>
<td>
{contract.state.withdrawInput?
Expand Down Expand Up @@ -278,7 +291,7 @@ const YourTokenPlans: React.FC<YourTokenPlansProps> = ({runtimeURL,marloweScanUR
<td><b className='text-secondary'>Closed</b> <br/> <span style={{fontSize :'smaller', whiteSpace:'nowrap'}}>({displayCloseCondition(contract.state.closeCondition)})</span></td>
<td>{contract.state.scheme.frequency}</td>
<td>{contract.state.scheme.numberOfPeriods.toString()}</td>
<td>{formatADAs(contract.state.scheme.expectedInitialDeposit.amount)}</td>
<td><span style={{whiteSpace:'nowrap'}}>{formatADAs(contract.state.scheme.expectedInitialDeposit.amount)}</span></td>
<td> Closed </td>
<td>
</td>
Expand All @@ -293,27 +306,4 @@ const YourTokenPlans: React.FC<YourTokenPlansProps> = ({runtimeURL,marloweScanUR
);
};



export type CurrencyF = String
export type WholeNumberF = string
export type DecimalF = string
const formatADAs = (lovelaces: bigint, isMainnet: Boolean = false, currencyName: string = "₳"): string=> {
const adas = (Math.trunc(Number(lovelaces).valueOf() / 1_000_000))
const decimalADAs = (lovelaces % 1_000_000n)
const currency = isMainnet ? currencyName : "t" + currencyName
if (decimalADAs === 0n)
return adas.toString() + ' ' + currency;
else
return adas.toString() + ' ' + decimalADAs.toString().padStart(6, '0') + ' ' + currency;
}

const cssOverrideSpinnerCentered
= ({display: "block",
marginLeft: "auto",
marginRight:"auto",
height: "auto",
witdth : "20px",
paddingTop: "10px"})

export default YourTokenPlans;
Loading

0 comments on commit 72c7e12

Please sign in to comment.