feat(dashboard-v2): proper copies on user settings pages + fix for account removal redirection
This commit is contained in:
parent
38407f6a31
commit
b572cdf72c
|
@ -1,7 +1,7 @@
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
import { useUser } from "../../contexts/user";
|
import { useUser } from "../../contexts/user";
|
||||||
import { SimpleUploadIcon } from "../Icons";
|
// import { SimpleUploadIcon } from "../Icons";
|
||||||
|
|
||||||
const AVATAR_PLACEHOLDER = "/images/avatar-placeholder.svg";
|
const AVATAR_PLACEHOLDER = "/images/avatar-placeholder.svg";
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@ export const AvatarUploader = (props) => {
|
||||||
>
|
>
|
||||||
<img src={imageUrl} className="w-[160px]" alt="" />
|
<img src={imageUrl} className="w-[160px]" alt="" />
|
||||||
</div>
|
</div>
|
||||||
|
{/* TODO: uncomment when avatar uploads work
|
||||||
<div className="flex justify-center">
|
<div className="flex justify-center">
|
||||||
<button
|
<button
|
||||||
className="flex items-center gap-4 hover:underline decoration-1 decoration-dashed underline-offset-2 decoration-gray-400"
|
className="flex items-center gap-4 hover:underline decoration-1 decoration-dashed underline-offset-2 decoration-gray-400"
|
||||||
|
@ -28,8 +29,8 @@ export const AvatarUploader = (props) => {
|
||||||
>
|
>
|
||||||
<SimpleUploadIcon size={20} className="shrink-0" /> Upload profile picture
|
<SimpleUploadIcon size={20} className="shrink-0" /> Upload profile picture
|
||||||
</button>
|
</button>
|
||||||
{/* TODO: actual uploading */}
|
|
||||||
</div>
|
</div>
|
||||||
|
*/}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import dayjs from "dayjs";
|
import dayjs from "dayjs";
|
||||||
import relativeTime from "dayjs/plugin/relativeTime";
|
import relativeTime from "dayjs/plugin/relativeTime";
|
||||||
|
import prettyBytes from "pretty-bytes";
|
||||||
|
|
||||||
import { useUser } from "../../contexts/user";
|
import { useUser } from "../../contexts/user";
|
||||||
import useActivePlan from "../../hooks/useActivePlan";
|
import useActivePlan from "../../hooks/useActivePlan";
|
||||||
|
@ -28,17 +29,20 @@ const CurrentPlan = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div className="flex flex-col h-full">
|
||||||
<h4>{activePlan.name}</h4>
|
<h4>{activePlan.name}</h4>
|
||||||
<div className="text-palette-400">
|
<div className="text-palette-400 justify-between flex flex-col grow">
|
||||||
{activePlan.price === 0 && <p>100GB without paying a dime! 🎉</p>}
|
{activePlan.price === 0 && activePlan.limits && (
|
||||||
|
<p>{prettyBytes(activePlan.limits.storageLimit)} without paying a dime! 🎉</p>
|
||||||
|
)}
|
||||||
{activePlan.price !== 0 &&
|
{activePlan.price !== 0 &&
|
||||||
(user.subscriptionCancelAtPeriodEnd ? (
|
(user.subscriptionCancelAtPeriodEnd ? (
|
||||||
<p>Your subscription expires {dayjs(user.subscribedUntil).fromNow()}</p>
|
<p>Your subscription expires {dayjs(user.subscribedUntil).fromNow()}</p>
|
||||||
) : (
|
) : (
|
||||||
<p className="first-letter:uppercase">{dayjs(user.subscribedUntil).fromNow(true)} until the next payment</p>
|
<p className="first-letter:uppercase">{dayjs(user.subscribedUntil).fromNow(true)} until the next payment</p>
|
||||||
))}
|
))}
|
||||||
<LatestPayment user={user} />
|
|
||||||
|
{user.subscriptionStatus && <LatestPayment user={user} />}
|
||||||
<SuggestedPlan plans={plans} activePlan={activePlan} />
|
<SuggestedPlan plans={plans} activePlan={activePlan} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,8 +1,19 @@
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
|
import styled from "styled-components";
|
||||||
|
|
||||||
import { PageContainer } from "../PageContainer";
|
import { PageContainer } from "../PageContainer";
|
||||||
|
|
||||||
|
const FooterLink = styled.a.attrs({
|
||||||
|
className: "text-palette-400 underline decoration-dotted decoration-offset-4 decoration-1",
|
||||||
|
rel: "noreferrer",
|
||||||
|
target: "_blank",
|
||||||
|
})``;
|
||||||
|
|
||||||
export const Footer = () => (
|
export const Footer = () => (
|
||||||
<PageContainer className="font-content text-palette-300 py-4">
|
<PageContainer className="font-content text-palette-300 py-4">
|
||||||
<p>© Skynet Labs Inc. All rights reserved.</p>
|
<p>
|
||||||
|
Made by <FooterLink href="https://skynetlabs.com">Skynet Labs</FooterLink>. Open-sourced{" "}
|
||||||
|
<FooterLink href="https://github.com/SkynetLabs/skynet-webportal">on Github</FooterLink>.
|
||||||
|
</p>
|
||||||
</PageContainer>
|
</PageContainer>
|
||||||
);
|
);
|
||||||
|
|
|
@ -118,7 +118,7 @@ const Uploader = ({ mode }) => {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{uploads.length > 0 && (
|
{uploads.length > 0 && (
|
||||||
<div className="flex flex-col space-y-4 py-10">
|
<div className="flex flex-col space-y-4 pt-6 pb-10">
|
||||||
{uploads.map((upload) => (
|
{uploads.map((upload) => (
|
||||||
<UploaderItem key={upload.id} onUploadStateChange={onUploadStateChange} upload={upload} />
|
<UploaderItem key={upload.id} onUploadStateChange={onUploadStateChange} upload={upload} />
|
||||||
))}
|
))}
|
||||||
|
|
|
@ -34,8 +34,9 @@ export const AccountRemovalForm = ({ abort, onSuccess }) => {
|
||||||
<Form className="flex flex-col gap-4">
|
<Form className="flex flex-col gap-4">
|
||||||
<div>
|
<div>
|
||||||
<h4>Delete account</h4>
|
<h4>Delete account</h4>
|
||||||
|
<p>This will completely delete your account.</p>
|
||||||
<p>
|
<p>
|
||||||
This will completely delete your account. <strong>This process can't be undone.</strong>
|
<strong>This process cannot be undone.</strong>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -38,8 +38,8 @@ const ExportPage = () => {
|
||||||
<section>
|
<section>
|
||||||
<h4>Export</h4>
|
<h4>Export</h4>
|
||||||
<p>
|
<p>
|
||||||
Et quidem exercitus quid ex eo delectu rerum, quem modo ista sis aequitate. Probabo, inquit, modo dixi,
|
Select the items you want to export. You can use this data to migrate your account to another Skynet
|
||||||
constituto.
|
portal.
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
<hr />
|
<hr />
|
||||||
|
|
|
@ -8,6 +8,10 @@ import { Modal } from "../../components/Modal/Modal";
|
||||||
import { AccountRemovalForm } from "../../components/forms/AccountRemovalForm";
|
import { AccountRemovalForm } from "../../components/forms/AccountRemovalForm";
|
||||||
import { Alert } from "../../components/Alert";
|
import { Alert } from "../../components/Alert";
|
||||||
import { Metadata } from "../../components/Metadata";
|
import { Metadata } from "../../components/Metadata";
|
||||||
|
import HighlightedLink from "../../components/HighlightedLink";
|
||||||
|
import { AvatarUploader } from "../../components/AvatarUploader/AvatarUploader";
|
||||||
|
import { useMedia } from "react-use";
|
||||||
|
import theme from "../../lib/theme";
|
||||||
|
|
||||||
const State = {
|
const State = {
|
||||||
Pure: "PURE",
|
Pure: "PURE",
|
||||||
|
@ -19,10 +23,16 @@ const AccountPage = () => {
|
||||||
const { user, mutate: reloadUser } = useUser();
|
const { user, mutate: reloadUser } = useUser();
|
||||||
const [state, setState] = useState(State.Pure);
|
const [state, setState] = useState(State.Pure);
|
||||||
const [removalInitiated, setRemovalInitiated] = useState(false);
|
const [removalInitiated, setRemovalInitiated] = useState(false);
|
||||||
|
const isLargeScreen = useMedia(`(min-width: ${theme.screens.xl})`);
|
||||||
|
|
||||||
const prompt = () => setRemovalInitiated(true);
|
const prompt = () => setRemovalInitiated(true);
|
||||||
const abort = () => setRemovalInitiated(false);
|
const abort = () => setRemovalInitiated(false);
|
||||||
|
|
||||||
|
const onAccountRemoved = useCallback(async () => {
|
||||||
|
await reloadUser(null);
|
||||||
|
await navigate("/auth/login");
|
||||||
|
}, [reloadUser]);
|
||||||
|
|
||||||
const onSettingsUpdated = useCallback(
|
const onSettingsUpdated = useCallback(
|
||||||
async (updatedState) => {
|
async (updatedState) => {
|
||||||
try {
|
try {
|
||||||
|
@ -45,14 +55,7 @@ const AccountPage = () => {
|
||||||
</Metadata>
|
</Metadata>
|
||||||
<div className="flex flex-col xl:flex-row">
|
<div className="flex flex-col xl:flex-row">
|
||||||
<div className="flex flex-col gap-10 lg:shrink-0 lg:max-w-[576px] xl:max-w-[524px]">
|
<div className="flex flex-col gap-10 lg:shrink-0 lg:max-w-[576px] xl:max-w-[524px]">
|
||||||
<section>
|
|
||||||
<h4>Account</h4>
|
<h4>Account</h4>
|
||||||
<p>
|
|
||||||
Tum dicere exorsus est laborum et quasi involuta aperiri, altera prompta et expedita. Primum igitur,
|
|
||||||
inquit, modo ista sis aequitate.
|
|
||||||
</p>
|
|
||||||
</section>
|
|
||||||
<hr />
|
|
||||||
<section className="flex flex-col gap-8">
|
<section className="flex flex-col gap-8">
|
||||||
{state === State.Failure && (
|
{state === State.Failure && (
|
||||||
<Alert $variant="error">There was an error processing your request. Please try again later.</Alert>
|
<Alert $variant="error">There was an error processing your request. Please try again later.</Alert>
|
||||||
|
@ -63,7 +66,23 @@ const AccountPage = () => {
|
||||||
<hr />
|
<hr />
|
||||||
<section>
|
<section>
|
||||||
<h6 className="text-palette-400">Delete account</h6>
|
<h6 className="text-palette-400">Delete account</h6>
|
||||||
<p>This will completely delete your account. This process can't be undone.</p>
|
<div className="my-4">
|
||||||
|
<p>
|
||||||
|
This action will delete your account and <strong>cannot be undone</strong>.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Your uploaded files will remain accessible while any portal continues to{" "}
|
||||||
|
<HighlightedLink
|
||||||
|
as="a"
|
||||||
|
href="https://support.skynetlabs.com/key-concepts/faqs#what-is-pinning"
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
>
|
||||||
|
pin
|
||||||
|
</HighlightedLink>{" "}
|
||||||
|
them to Skynet.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={prompt}
|
onClick={prompt}
|
||||||
|
@ -73,9 +92,12 @@ const AccountPage = () => {
|
||||||
</button>
|
</button>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="flex w-full justify-start xl:justify-end">
|
||||||
|
{isLargeScreen && <AvatarUploader className="flex flex-col gap-4" />}
|
||||||
|
</div>
|
||||||
{removalInitiated && (
|
{removalInitiated && (
|
||||||
<Modal onClose={abort} className="text-center">
|
<Modal onClose={abort} className="text-center">
|
||||||
<AccountRemovalForm abort={abort} onSuccess={() => navigate("/auth/login")} />
|
<AccountRemovalForm abort={abort} onSuccess={onAccountRemoved} />
|
||||||
</Modal>
|
</Modal>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -18,18 +18,13 @@ const NotificationsPage = () => {
|
||||||
<section>
|
<section>
|
||||||
{/* TODO: saves on change */}
|
{/* TODO: saves on change */}
|
||||||
<Switch onChange={console.info.bind(console)} labelClassName="!items-start flex-col md:flex-row">
|
<Switch onChange={console.info.bind(console)} labelClassName="!items-start flex-col md:flex-row">
|
||||||
I agreee to get the latest news, updates and special offers delivered to my email inbox.
|
I agree to receive emails of the latest news, updates and offers.
|
||||||
</Switch>
|
</Switch>
|
||||||
</section>
|
</section>
|
||||||
<hr />
|
<hr />
|
||||||
<section>
|
<section>
|
||||||
<h6 className="text-palette-300">Statistics</h6>
|
<h6 className="text-palette-300">Statistics</h6>
|
||||||
{/* TODO: proper content :) */}
|
<p>Check below to be notified by email when your usage approaches your plan's limits.</p>
|
||||||
<p>
|
|
||||||
Si sine causa, nollem me tamen laudandis maioribus meis corrupisti nec in malis. Si sine causa, mox
|
|
||||||
videro.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<ul className="mt-7 flex flex-col gap-2">
|
<ul className="mt-7 flex flex-col gap-2">
|
||||||
<li>
|
<li>
|
||||||
{/* TODO: saves on change */}
|
{/* TODO: saves on change */}
|
||||||
|
@ -37,7 +32,7 @@ const NotificationsPage = () => {
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
{/* TODO: saves on change */}
|
{/* TODO: saves on change */}
|
||||||
<Switch onChange={console.info.bind(console)}>File limit</Switch>
|
<Switch onChange={console.info.bind(console)}>Files limit</Switch>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</section>
|
</section>
|
||||||
|
|
Reference in New Issue