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

Implement UI for certificate #232

Merged
merged 1 commit into from
Feb 20, 2023
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
41 changes: 41 additions & 0 deletions app/components/certificate/certificate-available.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Divider } from '@chakra-ui/react';

import Description from './description';
import CertificateDisplay from './certificate-display';

interface CertificateAvailableProps {
validFrom: Date;
validTo: Date;
publicKey: string;
privateKey: string;
}

export default function CertificateAvailable({
validFrom,
validTo,
publicKey,
privateKey,
}: CertificateAvailableProps) {
return (
<>
<Description
description="Certificate: Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s"
certRequested={true}
validFrom={validFrom}
validTo={validTo}
/>
<Divider />
<CertificateDisplay
title="Public Key"
value={publicKey}
description="Public: Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s"
/>
<Divider />
<CertificateDisplay
title="Private Key"
value={privateKey}
description="Private: Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s"
/>
</>
);
}
99 changes: 99 additions & 0 deletions app/components/certificate/certificate-display.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import {
Flex,
Box,
HStack,
Text,
Heading,
Tooltip,
IconButton,
Accordion,
AccordionItem,
AccordionButton,
AccordionIcon,
AccordionPanel,
useToast,
} from '@chakra-ui/react';
import { DownloadIcon, CopyIcon } from '@chakra-ui/icons';

interface CertificateDisplayProps {
title: string;
value: string;
description: string;
Ririio marked this conversation as resolved.
Show resolved Hide resolved
}

export default function CertificateDisplay({ title, description, value }: CertificateDisplayProps) {
const toast = useToast();

function onCopy() {
navigator.clipboard.writeText(value);
toast({
title: `${title} was copied to the clipboard`,
position: 'bottom-right',
status: 'success',
});
}

return (
<Flex flexDirection="column" gap="5">
<Flex flexDirection="column" gap="4">
<HStack gap="4">
<Heading as="h4" size="sm">
{title}
</Heading>
<Tooltip label={`Copy ${title}`}>
<IconButton
backgroundColor="transparent"
color="black"
size="xs"
_hover={{
background: 'whitesmoke',
color: 'teal.500',
}}
aria-label="Copy to Clipboard"
icon={<CopyIcon fontSize="md" />}
onClick={() => onCopy()}
/>
</Tooltip>
<Tooltip label={`Download ${title}`}>
<IconButton
backgroundColor="transparent"
color="black"
size="xs"
_hover={{
background: 'brand.500',
color: 'white',
}}
aria-label="Download"
icon={
<DownloadIcon
fontSize="md"
onClick={() =>
toast({
title: `Downloading ${title}`,
position: 'bottom-right',
status: 'success',
})
}
/>
}
/>
</Tooltip>
</HStack>
<Text>{description}</Text>
<Accordion allowMultiple>
<AccordionItem>
<AccordionButton>
<Box as="span" flex="1" textAlign="left">
Show/Hide
</Box>
<AccordionIcon />
</AccordionButton>
<AccordionPanel>
<Text>{value}</Text>
</AccordionPanel>
</AccordionItem>
</Accordion>
</Flex>
</Flex>
);
}
41 changes: 41 additions & 0 deletions app/components/certificate/certificate-request.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Flex, Heading, Text, HStack, Button } from '@chakra-ui/react';

import Description from './description';

interface CertificateRequestViewProps {
subject: string;
validFrom: Date;
validTo: Date;
onRequest: () => void;
}

export default function CertificateRequestView({
Ririio marked this conversation as resolved.
Show resolved Hide resolved
subject,
validFrom,
validTo,
onRequest,
}: CertificateRequestViewProps) {
return (
<Flex flexDirection="column" gap="5" width="4xl">
<Description
description="Initial: Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s"
certRequested={false}
validFrom={validFrom}
validTo={validTo}
/>
<Flex flexDirection="column" gap="1">
<Heading as="h3" size="md" marginBottom="3">
Domain Name
</Heading>
<Text>Lorem Ipsum is simply dummy text of the printing and typesetting industry</Text>

<HStack>
<Text fontWeight="bold">Domain Name:</Text> <Text>{subject}</Text>
</HStack>
</Flex>
<Button width="3xs" shadow="xl" onClick={onRequest}>
Request a Certificate
</Button>
</Flex>
);
}
36 changes: 36 additions & 0 deletions app/components/certificate/description.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { Flex, Heading, Text, HStack, VStack } from '@chakra-ui/react';

interface DescriptionSectionProps {
certRequested: boolean;
validFrom: Date;
validTo: Date;
description: string;
}

export default function DescriptionSection({
certRequested,
validFrom,
validTo,
description,
}: DescriptionSectionProps) {
return (
<Flex flexDirection="column" gap="3" marginTop="14">
<Heading as="h1" size="xl">
Certificate
</Heading>
<Text>{description}</Text>
{certRequested && (
<HStack gap="6" marginTop="2">
<VStack>
<Text fontWeight="bold">Created On</Text>
<Text>{validFrom.toDateString()}</Text>
</VStack>
<VStack>
<Text fontWeight="bold">Expires On</Text>
<Text>{validTo.toDateString()}</Text>
</VStack>
</HStack>
)}
</Flex>
);
}
18 changes: 18 additions & 0 deletions app/components/certificate/loading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Center, Flex, Box, Image, Heading } from '@chakra-ui/react';

import undrawSvg from 'img/undraw_processing_re_tbdu.svg';
humphd marked this conversation as resolved.
Show resolved Hide resolved

export default function LoadingView() {
return (
<Center paddingY="24">
<Flex flexDirection="column" width="5xl" textAlign="center" gap="5">
<Box>
<Image src={undrawSvg} />
</Box>
<Heading as="h2" size="xl" fontFamily="heading" fontWeight="light" color="brand.500">
We have received your request, and will notify you when your certificate is ready
</Heading>
</Flex>
</Center>
);
}
63 changes: 57 additions & 6 deletions app/routes/__index/certificate/index.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,62 @@
import { Heading } from '@chakra-ui/react';
import { Flex, Center } from '@chakra-ui/react';
import type { Certificate } from '@prisma/client';
import { useState } from 'react';

import Loading from '~/components/certificate/loading';

import CertificateAvailable from '~/components/certificate/certificate-available';
import CertificateRequestView from '~/components/certificate/certificate-request';

export default function CertificateIndexRoute() {
const [certificateRequested, setCertificateRequested] = useState(false);
const [loading, setLoading] = useState(false);

const currentDate: Date = new Date(2023, 2);

const certificate: Certificate = {
id: 1,
username: 'user_test',
subject: `*.user_test.example.com`,
certificate:
'Public----BEGIN CERTIFICATE-----MIIFMjCCAxoCCQCVordquLnq8TANBgkqhkiG9w0BAQUFADBbMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRQwEgYDVQQDEwtleGFtcGxlLmNvbTAeFw0xNzA5MTQxNDMzMTRaFw0xODA5MTQxNDMzMTRaMFsxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxFDASBgNVBAMTC2V4YW1wbGUuY29tMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAwi2PYBNGl1n78niRGDKgcsWK03TcTeVbQ1HztA57Rr1iDHAZNx3Mv4E/Sha8VKbKoshcmUcOS3AlmbIZX+7+9c7lL2oD+vtUZF1YUR/69fWuO72wk6fKj/eofxH9Ud5KFje8qrYZdJWKkPMdWlYgjD6qpA5wl60NiuxmUr44ADZDytqHzNThN3wrFruz74PcMfakcSUMxkh98LuNeGtqHpEAw+wliko3oDD4PanvDvp5mRgiQVKHEGT7dm85Up+W1iJKJ65fkc/j940MaLbdISZYYCT5dtPgCGKCHgVuVrY+OXFJrD3TTm94ILsR/BkS/VSKNigGVPXg3q8tgIS++k13CzLUO0PNRMuod1RD9j5NEc2CVic9rcH06ugZyHlOcuVvvRsPGd52BPn+Jf1aePKPPQHxT9i5GOs80CJw0eduZCDZB32biRYNwUtjFkHbu8ii2IGkvhnWonjd4w5wOldG+RPr+XoFCIaHp5TszQ+HnUTLIXKtBgzzCKjK4eZqrck7xpo5B5m5V7EUxBze2LYVky+GsDsqL8CggQqJL4ZKuZVoxgPwhnDy5nMs057NCU9EnXcauMW9UEqEHu5NXnmGJrCvQ56wjYN3lgvCHEtmIpsRjCCWaBJYiawu1J5ZAf1yGTVNh8pEvO//zL9ImUxrSfOGUeFiN1tzSFlTfbcCAwEAATANBgkqhkiG9w0BAQUFAAOCAgEAdZZpgWv79CgF5ny6HmMaYgsXJKJyQE9RhJ1cmzDY8KAF+nzT7q4Pgt3WbA9bpdji7C0WqKjX7hLipqhgFnqb8qZcodEKhX788qBj4X45+4nT6QipyJlz5x6KcCn/v9gQNKks7U+dBlqquiVfbXaa1EAKMeGtqinf+Y51nR/fBcr/P9TBnSJqH61KDO3qrE5KGTwHQ9VXoeKyeppGt5sYf8G0vwoHhtPTOO8TuLEIlFcXtzbC3zAtmQj6Su//fI5yjuYTkiayxMx8nCGrQhQSXdC8gYpYd0os7UY01DVu4BTCXEvf0GYXtiGJeG8lQT/eu7WdK83uJ93U/BMYzoq4lSVcqY4LNxlfAQXKhaAbioA5XyT7co7FQ0g+s2CGBUKa11wPDe8M2GVLPsxT2bXDQap5DQyVIuTwjtgL0tykGxPJPAnL2zuUy6T3/YzrWaJ9Os+6mUCVdLnXtDgZ10Ujel7mq6wo9Ns+u07grXZkXpmJYnJXBrwOsY8KZa5vFwgJrDXhWe+Fmgt1EP5VIqRCQAxH2iYvAaELi8udbN/ZiUU3K9t79MP/M3U/tEWAubHXsaAv03jRy43X0VjlZHmagU/4dU7RBWfyuwRarYIXLNT2FCd2z4kd3fsL3rB5iI+RH0uoNuOa1+UApfFCv0O65TYkp5jEWSlU8PhKYD43nXA=-----END CERTIFICATE-----',
orderUrl: `orderUrl.example.com`,
privateKey:
'Private----BEGIN CERTIFICATE-----MIIFMjCCAxoCCQCVordquLnq8TANBgkqhkiG9w0BAQUFADBbMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRQwEgYDVQQDEwtleGFtcGxlLmNvbTAeFw0xNzA5MTQxNDMzMTRaFw0xODA5MTQxNDMzMTRaMFsxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxFDASBgNVBAMTC2V4YW1wbGUuY29tMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAwi2PYBNGl1n78niRGDKgcsWK03TcTeVbQ1HztA57Rr1iDHAZNx3Mv4E/Sha8VKbKoshcmUcOS3AlmbIZX+7+9c7lL2oD+vtUZF1YUR/69fWuO72wk6fKj/eofxH9Ud5KFje8qrYZdJWKkPMdWlYgjD6qpA5wl60NiuxmUr44ADZDytqHzNThN3wrFruz74PcMfakcSUMxkh98LuNeGtqHpEAw+wliko3oDD4PanvDvp5mRgiQVKHEGT7dm85Up+W1iJKJ65fkc/j940MaLbdISZYYCT5dtPgCGKCHgVuVrY+OXFJrD3TTm94ILsR/BkS/VSKNigGVPXg3q8tgIS++k13CzLUO0PNRMuod1RD9j5NEc2CVic9rcH06ugZyHlOcuVvvRsPGd52BPn+Jf1aePKPPQHxT9i5GOs80CJw0eduZCDZB32biRYNwUtjFkHbu8ii2IGkvhnWonjd4w5wOldG+RPr+XoFCIaHp5TszQ+HnUTLIXKtBgzzCKjK4eZqrck7xpo5B5m5V7EUxBze2LYVky+GsDsqL8CggQqJL4ZKuZVoxgPwhnDy5nMs057NCU9EnXcauMW9UEqEHu5NXnmGJrCvQ56wjYN3lgvCHEtmIpsRjCCWaBJYiawu1J5ZAf1yGTVNh8pEvO//zL9ImUxrSfOGUeFiN1tzSFlTfbcCAwEAATANBgkqhkiG9w0BAQUFAAOCAgEAdZZpgWv79CgF5ny6HmMaYgsXJKJyQE9RhJ1cmzDY8KAF+nzT7q4Pgt3WbA9bpdji7C0WqKjX7hLipqhgFnqb8qZcodEKhX788qBj4X45+4nT6QipyJlz5x6KcCn/v9gQNKks7U+dBlqquiVfbXaa1EAKMeGtqinf+Y51nR/fBcr/P9TBnSJqH61KDO3qrE5KGTwHQ9VXoeKyeppGt5sYf8G0vwoHhtPTOO8TuLEIlFcXtzbC3zAtmQj6Su//fI5yjuYTkiayxMx8nCGrQhQSXdC8gYpYd0os7UY01DVu4BTCXEvf0GYXtiGJeG8lQT/eu7WdK83uJ93U/BMYzoq4lSVcqY4LNxlfAQXKhaAbioA5XyT7co7FQ0g+s2CGBUKa11wPDe8M2GVLPsxT2bXDQap5DQyVIuTwjtgL0tykGxPJPAnL2zuUy6T3/YzrWaJ9Os+6mUCVdLnXtDgZ10Ujel7mq6wo9Ns+u07grXZkXpmJYnJXBrwOsY8KZa5vFwgJrDXhWe+Fmgt1EP5VIqRCQAxH2iYvAaELi8udbN/ZiUU3K9t79MP/M3U/tEWAubHXsaAv03jRy43X0VjlZHmagU/4dU7RBWfyuwRarYIXLNT2FCd2z4kd3fsL3rB5iI+RH0uoNuOa1+UApfFCv0O65TYkp5jEWSlU8PhKYD43nXA=-----END CERTIFICATE-----',
validFrom: currentDate,
validTo: new Date(currentDate.getFullYear(), currentDate.getMonth() + 6),
};

function onRequest() {
setLoading(true);
setTimeout(() => {
setCertificateRequested(true);
setLoading(false);
}, 5000);
}

if (loading) {
return <Loading />;
}

return (
<div>
<Heading as="h1" size="3xl">
Certificate Info or option to request a certificate
</Heading>
</div>
<Center>
<Flex flexDirection="column" gap="5" width="4xl">
{certificateRequested ? (
<CertificateAvailable
publicKey={certificate.certificate}
privateKey={certificate.privateKey}
validFrom={certificate.validFrom}
validTo={certificate.validTo}
/>
) : (
<CertificateRequestView
subject={certificate.subject}
validFrom={certificate.validFrom}
validTo={certificate.validTo}
onRequest={onRequest}
/>
)}
</Flex>
</Center>
);
}
26 changes: 26 additions & 0 deletions img/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
unDraw License

Copyright 2023 Katerina Limpitsouni

All images, assets and vectors published on unDraw can be used for free.
You can use them for noncommercial and commercial purposes. You do not
need to ask permission from or provide credit to the creator or unDraw.

More precisely, unDraw grants you an nonexclusive, worldwide copyright
license to download, copy, modify, distribute, perform, and use the assets
provided from unDraw for free, including for commercial purposes, without
permission from or attributing the creator or unDraw. This license does not
include the right to compile assets, vectors or images from unDraw to
replicate a similar or competing service, in any form or distribute the assets
in packs or otherwise. This extends to automated and non-automated ways
to link, embed, scrape, search or download the assets included on the
website without our consent.

Regarding brand logos that are included:

Are registered trademarks of their respected owners. Are included on a
promotional basis and do not represent an association with unDraw or its
users. Do not indicate any kind of endorsement of the trademark holder
towards unDraw, nor vice versa. Are provided with the sole purpose to
represent the actual brand/service/company that has registered the
trademark and must not be used otherwise.
1 change: 1 addition & 0 deletions img/undraw_processing_re_tbdu.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.