Final polish + cleaning

This commit is contained in:
Adi Thakral 2021-04-05 11:00:14 -04:00 committed by Steven Xu
parent ba210c7c4e
commit 7b07f8a9dc
10 changed files with 46 additions and 96 deletions

View File

@ -0,0 +1,4 @@
.input {
width: 100%;
padding-right: 16px;
}

View File

@ -1,5 +1,6 @@
import React from "react"; import React from "react";
import { Draggable } from "react-beautiful-dnd"; import { Draggable } from "react-beautiful-dnd";
import styles from "./Link.module.css";
export type EditableLink = { export type EditableLink = {
name: string; name: string;
@ -56,6 +57,7 @@ const Link: React.FC<LinkProps> = ({ index, link, onChange, onDelete }) => {
type="text" type="text"
placeholder="Edit Title" placeholder="Edit Title"
value={link.name} value={link.name}
className={styles.input}
onChange={(e) => onChange({ ...link, name: e.target.value })} onChange={(e) => onChange({ ...link, name: e.target.value })}
/> />
@ -74,6 +76,7 @@ const Link: React.FC<LinkProps> = ({ index, link, onChange, onDelete }) => {
type="url" type="url"
placeholder="https://url" placeholder="https://url"
value={link.url} value={link.url}
className={styles.input}
onChange={(e) => onChange({ ...link, url: e.target.value })} onChange={(e) => onChange({ ...link, url: e.target.value })}
/> />

View File

@ -15,26 +15,26 @@ interface EditorProps {
const Editor: React.FC<EditorProps> = ({ links, setLinks }) => { const Editor: React.FC<EditorProps> = ({ links, setLinks }) => {
const { displayDragDrop } = useDragDrop(); const { displayDragDrop } = useDragDrop();
const { headers } = useAuth(); const { headers } = useAuth();
const [formState, setFormState] = useState<EditableLink[]>(links); const [editableLinks, setEditableLinks] = useState<EditableLink[]>(links);
useEffect(() => { useEffect(() => {
setFormState(links); setEditableLinks(links);
}, [links]); }, [links]);
const handleOnDragEnd = (result: DropResult) => { const handleOnDragEnd = (result: DropResult) => {
if (!result?.destination) return; if (!result?.destination) return;
const items = Array.from(formState); const items = Array.from(editableLinks);
const [reorderedItem] = items.splice(result.source.index, 1); const [reorderedItem] = items.splice(result.source.index, 1);
items.splice(result.destination.index, 0, reorderedItem); items.splice(result.destination.index, 0, reorderedItem);
setFormState(items); setEditableLinks(items);
}; };
/*note that we need to make the new links name render with nothing*/ /*note that we need to make the new links name render with nothing*/
const handleOnClickAdd = () => const handleOnClickAdd = () =>
setFormState([ setEditableLinks([
...formState, ...editableLinks,
{ {
name: "", name: "",
url: "", url: "",
@ -44,21 +44,20 @@ const Editor: React.FC<EditorProps> = ({ links, setLinks }) => {
]); ]);
const onSubmit = async () => { const onSubmit = async () => {
// const res = await updateLinks(formState);
const res = await fetch("/api/editor/links", { const res = await fetch("/api/editor/links", {
method: "POST", method: "POST",
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
...headers, ...headers,
}, },
body: JSON.stringify({ links: formState }), body: JSON.stringify({ links: editableLinks }),
}); });
const updatedLinks = await res.json(); const updatedLinks = await res.json();
setLinks(updatedLinks); setLinks(updatedLinks);
}; };
const onCancel = () => { const onCancel = () => {
setFormState(links); setEditableLinks(links);
}; };
return ( return (
@ -80,22 +79,22 @@ const Editor: React.FC<EditorProps> = ({ links, setLinks }) => {
{...provided.droppableProps} {...provided.droppableProps}
ref={provided.innerRef} ref={provided.innerRef}
> >
{formState.map((link, index) => ( {editableLinks.map((link, index) => (
<Link <Link
key={index} key={index}
index={index} index={index}
link={link} link={link}
onChange={(newLink: EditableLink) => onChange={(newLink: EditableLink) =>
setFormState([ setEditableLinks([
...formState.slice(0, index), ...editableLinks.slice(0, index),
newLink, newLink,
...formState.slice(index + 1), ...editableLinks.slice(index + 1),
]) ])
} }
onDelete={() => onDelete={() =>
setFormState([ setEditableLinks([
...formState.slice(0, index), ...editableLinks.slice(0, index),
...formState.slice(index + 1), ...editableLinks.slice(index + 1),
]) ])
} }
/> />
@ -111,7 +110,7 @@ const Editor: React.FC<EditorProps> = ({ links, setLinks }) => {
<button <button
className="block flex py-2 items-center justify-center rounded-md bg-purple-600 hover:bg-purple-500 cursor-pointer text-white w-full disabled:opacity-50" className="block flex py-2 items-center justify-center rounded-md bg-purple-600 hover:bg-purple-500 cursor-pointer text-white w-full disabled:opacity-50"
onClick={onSubmit} onClick={onSubmit}
disabled={equal(formState, links)} disabled={equal(editableLinks, links)}
> >
Submit Submit
</button> </button>
@ -119,13 +118,13 @@ const Editor: React.FC<EditorProps> = ({ links, setLinks }) => {
<button <button
className="block flex py-2 items-center justify-center rounded-md bg-purple-600 hover:bg-purple-500 cursor-pointer text-white w-full disabled:opacity-50" className="block flex py-2 items-center justify-center rounded-md bg-purple-600 hover:bg-purple-500 cursor-pointer text-white w-full disabled:opacity-50"
onClick={onCancel} onClick={onCancel}
disabled={equal(formState, links)} disabled={equal(editableLinks, links)}
> >
Cancel Cancel
</button> </button>
</div> </div>
</div> </div>
<Preview links={formState} /> <Preview links={editableLinks.filter((link) => link.active)} />
</div> </div>
); );
}; };

View File

@ -1,27 +1,30 @@
import React, { ComponentPropsWithoutRef } from "react"; import React from "react";
import { Link } from "utils/types";
export interface Link { export interface Link {
name: string; name: string;
url: string; url: string;
} }
interface LinkProps extends ComponentPropsWithoutRef<"div"> { interface Props {
links: Link[]; links: Link[];
logClicks?: boolean;
} }
export const Links: React.FC<LinkProps> = ({ links, className }) => { export const Links: React.FC<Props> = ({ links, logClicks = false }) => {
const handleClick = (name: string, url: string) => const handleClick = (name: string, url: string) => {
fetch("/api/clicks", { if (logClicks) {
method: "POST", fetch("/api/clicks", {
headers: { method: "POST",
"Content-Type": "application/json", headers: {
}, "Content-Type": "application/json",
body: JSON.stringify({ name, url }), },
}); body: JSON.stringify({ name, url }),
});
}
};
return ( return (
<div <div
className={`text-s flex flex-col items-center w-full top-6 font-karla ${className}`} className={`text-s flex flex-col items-center w-full top-6 font-karla`}
> >
<img className="mb-3" src="csc_logo.png" alt="CSC Logo" width="100px" /> <img className="mb-3" src="csc_logo.png" alt="CSC Logo" width="100px" />
<h1 className="font-bold">@uwcsclub</h1> <h1 className="font-bold">@uwcsclub</h1>

View File

@ -1,9 +1,7 @@
import { Links } from "components/Links"; import { Link, Links } from "components/Links";
import React from "react"; import React from "react";
import styles from "./styles.module.css"; import styles from "./styles.module.css";
import { Link } from "utils/types";
interface PreviewProps { interface PreviewProps {
links: Link[]; links: Link[];
} }
@ -14,7 +12,9 @@ const Preview: React.FC<PreviewProps> = ({ links }) => {
<div <div
className={`box-border bg-white rounded-preview border-preview border-black ${styles.parent}`} className={`box-border bg-white rounded-preview border-preview border-black ${styles.parent}`}
> >
<Links links={links} className={styles.child} /> <div className={styles.child}>
<Links links={links} />
</div>
</div> </div>
</div> </div>
); );

View File

@ -1,3 +0,0 @@
{
"greeting": "Hello from JSON"
}

View File

@ -1,48 +0,0 @@
import React from "react";
import { GetStaticProps } from "next";
import GreetingJSON from "./hello-world.json";
import { fetchExample } from "utils/api";
interface Props {
greeting: string;
}
export const getStaticProps: GetStaticProps<Props> = async () => {
return {
props: { greeting: GreetingJSON.greeting }, // will be passed to the page component as props
// Next.js will attempt to re-generate the page:
// - When a request comes in
// - At most once every second
revalidate: 1,
};
};
function HelloWorld({ greeting }: Props): JSX.Element {
const [greetings, setGreetings] = React.useState([greeting]);
const getMoreGreetings = async () => {
const greetingFromBackend = await fetchExample();
setGreetings([
...greetings,
`"${greetingFromBackend}" --- ${new Date().toISOString()}`,
]);
};
return (
<div style={{ padding: "50px" }}>
<button
style={{ border: "2px solid black", padding: "5px" }}
onClick={getMoreGreetings}
>
Get greeting from the server
</button>
<ol style={{ listStyleType: "decimal" }}>
{greetings.map((greeting) => (
<li key={greeting}>{greeting}</li>
))}
</ol>
</div>
);
}
export default HelloWorld;

View File

@ -17,7 +17,7 @@ interface Props {
} }
const Home: React.FC<Props> = ({ links }) => { const Home: React.FC<Props> = ({ links }) => {
return <Links links={links} />; return <Links links={links} logClicks={true} />;
}; };
export default Home; export default Home;

View File

@ -1,4 +0,0 @@
export async function fetchExample(): Promise<string> {
const response = await fetch("/api");
return await response.text();
}

View File

@ -1,4 +0,0 @@
export interface Link {
name: string;
url: string;
}