mirror of
https://github.com/yangshun/tech-interview-handbook.git
synced 2025-07-28 12:43:12 +08:00
[offers][feat] Add toast (#417)
* [offers][feat] Add toasts * [offers][fix] Disable empty comments
This commit is contained in:
@ -1,9 +1,9 @@
|
||||
import { useRouter } from 'next/router';
|
||||
import { useState } from 'react';
|
||||
import { setTimeout } from 'timers';
|
||||
import { CheckIcon, DocumentDuplicateIcon } from '@heroicons/react/20/solid';
|
||||
import { BookmarkSquareIcon, EyeIcon } from '@heroicons/react/24/outline';
|
||||
import { Button, TextInput } from '@tih/ui';
|
||||
// Import { useState } from 'react';
|
||||
// import { setTimeout } from 'timers';
|
||||
import { DocumentDuplicateIcon } from '@heroicons/react/20/solid';
|
||||
import { EyeIcon } from '@heroicons/react/24/outline';
|
||||
import { Button, TextInput, useToast } from '@tih/ui';
|
||||
|
||||
import {
|
||||
copyProfileLink,
|
||||
@ -20,18 +20,18 @@ export default function OffersProfileSave({
|
||||
profileId,
|
||||
token,
|
||||
}: OfferProfileSaveProps) {
|
||||
const [linkCopied, setLinkCopied] = useState(false);
|
||||
const [isSaving, setSaving] = useState(false);
|
||||
const [isSaved, setSaved] = useState(false);
|
||||
const { showToast } = useToast();
|
||||
// Const [isSaving, setSaving] = useState(false);
|
||||
// const [isSaved, setSaved] = useState(false);
|
||||
const router = useRouter();
|
||||
|
||||
const saveProfile = () => {
|
||||
setSaving(true);
|
||||
setTimeout(() => {
|
||||
setSaving(false);
|
||||
setSaved(true);
|
||||
}, 5);
|
||||
};
|
||||
// Const saveProfile = () => {
|
||||
// setSaving(true);
|
||||
// setTimeout(() => {
|
||||
// setSaving(false);
|
||||
// setSaved(true);
|
||||
// }, 5);
|
||||
// };
|
||||
|
||||
return (
|
||||
<div className="flex w-full justify-center">
|
||||
@ -44,7 +44,7 @@ export default function OffersProfileSave({
|
||||
To keep you offer profile strictly anonymous, only people who have the
|
||||
link below can edit it.
|
||||
</p>
|
||||
<div className="mb-5 grid grid-cols-12 gap-4">
|
||||
<div className="mb-20 grid grid-cols-12 gap-4">
|
||||
<div className="col-span-11">
|
||||
<TextInput
|
||||
disabled={true}
|
||||
@ -59,17 +59,15 @@ export default function OffersProfileSave({
|
||||
label="Copy"
|
||||
variant="primary"
|
||||
onClick={() => {
|
||||
copyProfileLink(profileId, token), setLinkCopied(true);
|
||||
copyProfileLink(profileId, token);
|
||||
showToast({
|
||||
title: `Profile edit link copied to clipboard!`,
|
||||
variant: 'success',
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className="mb-20">
|
||||
{linkCopied && (
|
||||
<p className="text-purple-700">Link copied to clipboard!</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<p className="mb-5 text-gray-900">
|
||||
{/* <p className="mb-5 text-gray-900">
|
||||
If you do not want to keep the edit link, you can opt to save this
|
||||
profile under your user account. It will still only be editable by
|
||||
you.
|
||||
@ -83,7 +81,7 @@ export default function OffersProfileSave({
|
||||
variant="primary"
|
||||
onClick={saveProfile}
|
||||
/>
|
||||
</div>
|
||||
</div> */}
|
||||
<div>
|
||||
<Button
|
||||
icon={EyeIcon}
|
||||
|
@ -1,7 +1,13 @@
|
||||
import { signIn, useSession } from 'next-auth/react';
|
||||
import { useState } from 'react';
|
||||
import { ClipboardDocumentIcon, ShareIcon } from '@heroicons/react/24/outline';
|
||||
import { Button, HorizontalDivider, Spinner, TextArea } from '@tih/ui';
|
||||
import {
|
||||
Button,
|
||||
HorizontalDivider,
|
||||
Spinner,
|
||||
TextArea,
|
||||
useToast,
|
||||
} from '@tih/ui';
|
||||
|
||||
import ExpandableCommentCard from '~/components/offers/profile/comments/ExpandableCommentCard';
|
||||
|
||||
@ -30,6 +36,7 @@ export default function ProfileComments({
|
||||
const { data: session, status } = useSession();
|
||||
const [currentReply, setCurrentReply] = useState<string>('');
|
||||
const [replies, setReplies] = useState<Array<Reply>>();
|
||||
const { showToast } = useToast();
|
||||
|
||||
const commentsQuery = trpc.useQuery(
|
||||
['offers.comments.getComments', { profileId }],
|
||||
@ -51,6 +58,10 @@ export default function ProfileComments({
|
||||
});
|
||||
|
||||
function handleComment(message: string) {
|
||||
if (!currentReply.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isEditable) {
|
||||
// If it is with edit permission, send comment to API with username = null
|
||||
createCommentMutation.mutate(
|
||||
@ -104,7 +115,13 @@ export default function ProfileComments({
|
||||
label="Copy profile edit link"
|
||||
size="sm"
|
||||
variant="secondary"
|
||||
onClick={() => copyProfileLink(profileId, token)}
|
||||
onClick={() => {
|
||||
copyProfileLink(profileId, token);
|
||||
showToast({
|
||||
title: `Profile edit link copied to clipboard!`,
|
||||
variant: 'success',
|
||||
});
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<Button
|
||||
@ -115,7 +132,13 @@ export default function ProfileComments({
|
||||
label="Copy public link"
|
||||
size="sm"
|
||||
variant="secondary"
|
||||
onClick={() => copyProfileLink(profileId)}
|
||||
onClick={() => {
|
||||
copyProfileLink(profileId);
|
||||
showToast({
|
||||
title: `Public profile link copied to clipboard!`,
|
||||
variant: 'success',
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<h2 className="mt-2 mb-6 text-2xl font-bold">Discussions</h2>
|
||||
@ -131,7 +154,7 @@ export default function ProfileComments({
|
||||
<div className="mt-2 flex w-full justify-end">
|
||||
<div className="w-fit">
|
||||
<Button
|
||||
disabled={commentsQuery.isLoading}
|
||||
disabled={commentsQuery.isLoading || !currentReply.length}
|
||||
display="block"
|
||||
isLabelHidden={false}
|
||||
isLoading={createCommentMutation.isLoading}
|
||||
|
@ -43,6 +43,10 @@ export default function CommentCard({
|
||||
});
|
||||
|
||||
function handleReply() {
|
||||
if (!currentReply.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (token && token.length > 0) {
|
||||
// If it is with edit permission, send comment to API with username = null
|
||||
createCommentMutation.mutate(
|
||||
@ -132,6 +136,7 @@ export default function CommentCard({
|
||||
<div className="mt-2 flex w-full justify-end">
|
||||
<div className="w-fit">
|
||||
<Button
|
||||
disabled={!currentReply.length}
|
||||
display="block"
|
||||
isLabelHidden={false}
|
||||
isLoading={createCommentMutation.isLoading}
|
||||
|
@ -11,6 +11,7 @@ import type {
|
||||
OfferDisplayData,
|
||||
} from '~/components/offers/types';
|
||||
|
||||
import { useToast } from '~/../../../packages/ui/dist';
|
||||
import { convertMoneyToString } from '~/utils/offers/currency';
|
||||
import { getProfilePath } from '~/utils/offers/link';
|
||||
import { formatDate } from '~/utils/offers/time';
|
||||
@ -19,6 +20,7 @@ import { trpc } from '~/utils/trpc';
|
||||
import type { Profile, ProfileAnalysis, ProfileOffer } from '~/types/offers';
|
||||
|
||||
export default function OfferProfile() {
|
||||
const { showToast } = useToast();
|
||||
const ErrorPage = (
|
||||
<Error statusCode={404} title="Requested profile does not exist." />
|
||||
);
|
||||
@ -131,11 +133,18 @@ export default function OfferProfile() {
|
||||
const trpcContext = trpc.useContext();
|
||||
const deleteMutation = trpc.useMutation(['offers.profile.delete'], {
|
||||
onError: () => {
|
||||
alert('Error deleting profile'); // TODO: replace with toast
|
||||
showToast({
|
||||
title: `Error deleting offers profile.`,
|
||||
variant: 'failure',
|
||||
});
|
||||
},
|
||||
onSuccess: () => {
|
||||
trpcContext.invalidateQueries(['offers.profile.listOne']);
|
||||
router.push('/offers');
|
||||
showToast({
|
||||
title: `Offers profile successfully deleted!`,
|
||||
variant: 'success',
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -3,7 +3,6 @@ export function getProfileLink(profileId: string, token?: string) {
|
||||
}
|
||||
|
||||
export function copyProfileLink(profileId: string, token?: string) {
|
||||
// TODO: Add notification
|
||||
navigator.clipboard.writeText(getProfileLink(profileId, token));
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user