Final polish + cleaning
This commit is contained in:
parent
ba210c7c4e
commit
7b07f8a9dc
|
@ -0,0 +1,4 @@
|
||||||
|
.input {
|
||||||
|
width: 100%;
|
||||||
|
padding-right: 16px;
|
||||||
|
}
|
|
@ -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 })}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
|
@ -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>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
{
|
|
||||||
"greeting": "Hello from JSON"
|
|
||||||
}
|
|
|
@ -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;
|
|
|
@ -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;
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
export async function fetchExample(): Promise<string> {
|
|
||||||
const response = await fetch("/api");
|
|
||||||
return await response.text();
|
|
||||||
}
|
|
|
@ -1,4 +0,0 @@
|
||||||
export interface Link {
|
|
||||||
name: string;
|
|
||||||
url: string;
|
|
||||||
}
|
|
Loading…
Reference in New Issue