Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add sale end without vesting date #152

Merged
merged 8 commits into from
May 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ export function ProjectInfoCard(props: Props) {
{'Citizend token sale'}
</Text>

{vestingStart && (
{!!vestingStart && (
<>
<Text noMargin variant={'small'}>
{'Vesting starting at:'}
Expand Down
6 changes: 5 additions & 1 deletion packages/web/src/components/screens/dashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { ProjectInfoCard } from 'src/components/dashboard/project-info-card';
import { SaleForm } from 'src/components/dashboard/sale-form';
import { SaleState, useSale } from 'src/hooks/use-sale';
import { ShareReferralModal } from 'src/components/modals/share-referral-modal';
import { UnknownDate } from 'src/components/unknown-date';
import { Vesting } from 'src/components/vesting';
import { Web3Provider } from '@ethersproject/providers';
import { currencyConfig } from 'src/core/constants';
Expand Down Expand Up @@ -72,7 +73,9 @@ export function DashboardScreen() {
myContribution={formatCurrency(balance, currencyConfig.aUsd)}
price={formatCurrency(price, currencyConfig.aUsd)}
raised={formatCompactNumber(raised, currencyConfig.aUsd)}
vestingStart={formatFromUnix(vestingStart)}
vestingStart={
vestingStart === 0 ? undefined : formatFromUnix(vestingStart)
}
/>

{!isLoading && state === 'COUNTDOWN' && !isNaN(vestingStart) && (
Expand All @@ -82,6 +85,7 @@ export function DashboardScreen() {
/>
)}

{!isLoading && state === 'VESTING_UNKNOWN' && <UnknownDate />}
{!isLoading && state === 'SALE' && (
<SaleForm disabled={!kycApproved} tokenPrice={price} />
)}
Expand Down
64 changes: 64 additions & 0 deletions packages/web/src/components/unknown-date.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/**
* Module dependencies.
*/

import { Text } from 'src/components/core/text';
import React from 'react';
import styled from 'styled-components';

/**
* `Section` styled component.
*/

const Section = styled.section`
max-width: 100%;
overflow: hidden;
position: relative;
`;

/**
* `Container` styled component.
*/

const Container = styled.section`
margin: 0 auto;
max-width: 640px;
padding: 3rem 2rem 0;
text-align: center;
`;

/**
* `Title` styled component.
*/

const Title = styled(Text).attrs({ variant: 'lead' })`
display: block;
margin-bottom: 3rem;
`;

/**
* `Label` styled component.
*/

const Label = styled(Text).attrs({ variant: 'body' })`
margin: 0;
padding-top: 0.75rem;
`;

/**
* Export `UnknownDate` component.
*/

export function UnknownDate() {
return (
<Section>
<Container>
<Title>
{'Vesting will begin after the public sale has concluded'}
</Title>

<Label>{'Keep checking this page for updates.'}</Label>
</Container>
</Section>
);
}
16 changes: 1 addition & 15 deletions packages/web/src/components/vesting/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import { formatCurrency } from 'src/core/utils/formatters';
import { media } from 'src/styles/breakpoints';
import { useClaim, useRefund, useVesting } from 'src/hooks/use-vesting';
import React, { useMemo } from 'react';
import dayjs from 'src/core/utils/dayjs';
import styled from 'styled-components';

/**
Expand All @@ -28,19 +27,6 @@ const Grid = styled.section`
`}
`;

/**
* `getFirstDayOfNextMonth`.
*/

function getFirstDayOfNextMonth() {
const now = dayjs();

return now
.month(now.month() + 1)
.date(1)
.format('DD/MM/YYYY');
}

/**
* Export `Vesting` component.
*/
Expand All @@ -65,7 +51,7 @@ export function Vesting() {
return (
<Grid>
<InfoCard
nextRelease={getFirstDayOfNextMonth()}
nextRelease={vestingState.nextRelease}
tokens={tokens}
totalClaimed={totalClaimed}
/>
Expand Down
2 changes: 1 addition & 1 deletion packages/web/src/core/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export const currencyConfig = {
decimalPlaces: 12,
decimalPlacesToDisplay: 6,
skipTrailingZeros: true,
symbol: '$'
symbol: undefined
},
ctnd: {
currency: 'CTND',
Expand Down
64 changes: 48 additions & 16 deletions packages/web/src/core/utils/formatters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,13 +58,54 @@ export type DateTimeOptions = {
hideHour?: boolean;
};

/**
* `replaceCryptoSymbol` util.
*/

function replaceCryptoSymbol(value: string, options: CurrencyOptions) {
const { currency, symbol } = options;
const currencySymbol = symbol ?? currency;
const whitespace = size(symbol ?? currency) > 1 ? ' ' : '';

return value
.replace(/^BTC */, `${currencySymbol}${whitespace}`)
.replace(/^-BTC */, `${currencySymbol}${whitespace}`)
.replace(/ *BTC$/, `${whitespace}${currencySymbol}`);
}

/**
* `formatCryptoParts` util.
*/

function formatCryptoParts(
formattedParts: Intl.NumberFormatPart[],
options: CurrencyOptions
) {
const [currencyPart, literalPart, ...rest] = formattedParts;

// Force currency to the right side.
if (currencyPart.type === 'currency' && literalPart.type === 'literal') {
const switchedParts = [
...rest.map(({ value }) => value),
literalPart?.value,
currencyPart?.value
];

return replaceCryptoSymbol(switchedParts.join(''), options);
}

return replaceCryptoSymbol(
formattedParts.map(({ value }) => value).join(''),
options
);
}

/**
* Currency formatter.
*/

function currencyFormatter(options: NumberOptions): Intl.NumberFormat {
const { decimalPlacesToDisplay, skipTrailingZeros, ...rest } = options;

const maximumFractionDigits = Math.min(
decimalPlacesToDisplay ?? 2,
maximumDecimalPlaces
Expand Down Expand Up @@ -168,12 +209,7 @@ export function formatCurrency(
style: 'currency'
});

return formattedParts
.map(({ value }) => value)
.join('')
.replace(/^BTC */, `${currencySymbol}${whitespace}`)
.replace(/^-BTC */, `${currencySymbol}${whitespace}`)
.replace(/ *BTC$/, `${whitespace}${currencySymbol}`);
return formatCryptoParts(formattedParts, options);
} catch (error) {
return fallback;
}
Expand All @@ -188,7 +224,7 @@ export function formatCompactNumber(
value: NullableNumber,
options?: CurrencyOptions
): string {
const { currency, decimalPlacesToDisplay = 1, symbol } = options ?? {};
const { currency, decimalPlacesToDisplay = 1 } = options ?? {};
const numericValue = convertNumberToString(value ?? '0');
const [integer, fraction = ''] = numericValue.split('.');
const compactSignificantDigits = integer.length % 3 || 3;
Expand All @@ -210,19 +246,15 @@ export function formatCompactNumber(
style: currency ? 'currency' : undefined
}).format(truncatedValue);
} catch (error) {
const whitespace = size(symbol ?? currency) > 1 ? ' ' : '';

return new Intl.NumberFormat(locale, {
const formattedParts = new Intl.NumberFormat(locale, {
compactDisplay: 'short',
currency: 'BTC',
maximumSignificantDigits,
notation: 'compact',
style: currency ? 'currency' : undefined
})
.format(truncatedValue)
.replace(/^BTC */, `${symbol ?? currency}${whitespace}`)
.replace(/^-BTC */, `${symbol ?? currency}${whitespace}`)
.replace(/ *BTC$/, `${whitespace}${symbol ?? currency}`);
}).formatToParts(truncatedValue);

return formatCryptoParts(formattedParts, options);
}
}

Expand Down
15 changes: 10 additions & 5 deletions packages/web/src/hooks/use-app-status.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ const appState = {
comingSoon: 'SOON',
countdown: 'COUNTDOWN',
sale: 'SALE',
vesting: 'VESTING'
vesting: 'VESTING',
vestingUnknown: 'VESTING_UNKNOWN'
} as const;

/**
Expand Down Expand Up @@ -106,16 +107,20 @@ export function useAppStatus() {
vestingStart: !!vestingStart?.toNumber && vestingStart.toNumber()
});

if (dayjs().isAfter(vestingStartDate)) {
return getStatus('VESTING');
if (dayjs().isAfter(saleStartDate) && dayjs().isBefore(saleEndDate)) {
return getStatus('SALE');
}

if (vestingStart.eq(0)) {
return getStatus('VESTING_UNKNOWN');
}

if (dayjs().isAfter(saleEndDate) && dayjs().isBefore(vestingStartDate)) {
return getStatus('COUNTDOWN');
}

if (dayjs().isAfter(saleStartDate) && dayjs().isBefore(saleEndDate)) {
return getStatus('SALE');
if (dayjs().isAfter(vestingStartDate)) {
return getStatus('VESTING');
}

return getStatus('SOON');
Expand Down
32 changes: 22 additions & 10 deletions packages/web/src/hooks/use-vesting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
import { useCallback, useEffect, useState } from 'react';
import { useContracts } from 'src/context/contracts';
import { useWeb3React } from '@web3-react/core';
import dayjs from 'src/core/utils/dayjs';

/**
* Export `VestingState` type.
Expand All @@ -27,6 +28,19 @@ export type VestingState = {
tokens: string;
};

/**
* `getFirstDayOfNextMonth`.
*/

function getFirstDayOfNextMonth() {
const now = dayjs();

return now
.month(now.month() + 1)
.date(1)
.format('DD/MM/YYYY');
}

/**
* Export `useVesting` hook.
*/
Expand All @@ -45,25 +59,23 @@ export function useVesting() {
const { account } = useWeb3React<Web3Provider>();
const contracts = useContracts();
const getVestingState = useCallback(async () => {
if (!contracts?.vesting) {
if (!contracts?.vesting || !contracts?.sale1 || !contracts?.citizend) {
return;
}

try {
const claimableTotal = await contracts.vesting.claimable(account);
const claimed = await contracts.vesting.claimed(account);
const claimablePublic = await contracts.vesting.claimablePublic(account);
const refundable = await contracts.sale1.refundAmount(account);
const tokens = await contracts.citizend.balanceOf(account);
const claimablePrivate = await contracts.vesting.claimablePrivate(
account
);

setState({
alreadyClaimed: claimed.toString(),
claimEnabled: claimablePublic.gt(0),
claimable: claimablePublic.toString(),
nextRelease: 'TODO',
refundEnabled: claimablePrivate.gt(0),
refundable: claimablePrivate.toString(),
claimEnabled: claimableTotal.gt(0),
claimable: claimableTotal.toString(),
nextRelease: getFirstDayOfNextMonth(),
refundEnabled: refundable.gt(0),
refundable: refundable.toString(),
tokens: tokens.toString()
});
} catch (error) {
Expand Down