Skip to content

Commit

Permalink
Update webpack and eslint configurations, fix styling issues, and imp…
Browse files Browse the repository at this point in the history
…rove code readability
  • Loading branch information
YummyBacon5 authored Feb 2, 2024
1 parent 258aeae commit 755c6b9
Show file tree
Hide file tree
Showing 9 changed files with 67 additions and 56 deletions.
57 changes: 30 additions & 27 deletions backend/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

from random_word import RandomWords

from tinydb import TinyDB, Query
from tinydb import TinyDB, where
from tinydb.operations import increment, decrement

# -------------------------------------------
Expand All @@ -34,12 +34,6 @@
allow_origin_regex=r"^/api.*$", # Only allow CORS on /api
)

# -------------------------------------------

# Add the new keys into the database. So old data doesn't break everything
db.update({"downdoots": 0}, ~ Query().downdoots.exists())
db.update({"isRobot": False}, ~ Query().isRobot.exists())

# -------------------------------------------
# Input models

Expand Down Expand Up @@ -76,7 +70,7 @@ class SortByEnum(str, Enum):
UPDOOTS = "updoots"
DOWNDOOTS = "downdoots"
ID = "id"
CREATION_DATE = "date"
DATE = "date"
ALPHABETICAL = "alphabet"

# -------------------------------------------
Expand Down Expand Up @@ -134,24 +128,24 @@ async def upload_a_new_word(new_word: UploadWordFormat):

# Check if word is empty
if word == "":
raise HTTPException(status_code=400, detail="Word after trimming of white space cannot be empty")
raise HTTPException(status_code=400, detail="Word after trimming white space can't be empty")

# Check if word already exists
if db.search(Query().word == word):
if db.search(where("word") == word):
raise HTTPException(status_code=400, detail="Word already exists")

if description == "":
raise HTTPException(status_code=400, detail="Description cannot be empty")

record = {
"id": len(db),
"id": (max(db.all(), key=lambda x: x["id"])["id"] + 1) or 0,
"word": word,
"description": description,
"creationDate": new_word.creationDate or int(time.time()),
"uploader": uploader or "Unknown",
"updoots": 0,
"downdoots": 0,
"isRobot": False,
"isRobot": new_word.isRobot or False,
}

db.insert(record)
Expand All @@ -164,7 +158,7 @@ async def delete_a_word(req: DeleteWord):
raise HTTPException(status_code=403, detail="Unauthorised, invalid secret key")

# Check if the word exists
word = db.get(Query().id == req.id)
word = db.get(where("id") == req.id)
if not word:
raise HTTPException(status_code=404, detail="Word does not exist")

Expand All @@ -175,26 +169,29 @@ async def delete_a_word(req: DeleteWord):
async def update_words_updoot_count(req: UpdateUpdoot):
word_id = req.id

if not db.contains(Query().id == word_id):
if not db.contains(where("id") == word_id):
raise HTTPException(status_code=404, detail="Word does not exist")

if req.prevUpdootState == req.updootState:
raise HTTPException(status_code=400, detail="Cannot update the same updoot state")

if req.prevUpdootState != UpdootEnum.NONE:
db.update(decrement(req.prevUpdootState.value + "doots"), Query().id == word_id)
db.update(decrement(req.prevUpdootState.value + "doots"), where("id") == word_id)

if req.updootState != UpdootEnum.NONE:
db.update(increment(req.updootState.value + "doots"), Query().id == word_id)
db.update(increment(req.updootState.value + "doots"), where("id") == word_id)

return db.get(Query().id == word_id)
return db.get(where("id") == word_id)

@app.get("/api/get_all_words", response_model=list[Record])
async def get_all_words(
sortby: SortByEnum = SortByEnum.UPDOOTS, orderby: DirEnum = DirEnum.DESC
sortby: SortByEnum = SortByEnum.UPDOOTS, orderby: DirEnum = DirEnum.ASC
):
IS_REVERSED = orderby == DirEnum.ASC

# By default, Python sorts from lowest to highest
# So for asending to work (highest to lowest), it needs to be reversed

if sortby == SortByEnum.TOTALDOOTS:
return sorted(db.all(), key=lambda x: x["updoots"] - x["downdoots"], reverse=IS_REVERSED)

Expand All @@ -207,7 +204,7 @@ async def get_all_words(
elif sortby == SortByEnum.DOWNDOOTS:
return sorted(db.all(), key=lambda x: x["downdoots"], reverse=IS_REVERSED)

elif sortby == SortByEnum.CREATION_DATE:
elif sortby == SortByEnum.DATE:
return sorted(db.all(), key=lambda x: x["creationDate"], reverse=IS_REVERSED)

elif sortby == SortByEnum.ALPHABETICAL:
Expand All @@ -216,7 +213,7 @@ async def get_all_words(

@app.get("/api/get_word/{wordID}", response_model=Record)
async def get_word_by_ID(wordID: int):
response = db.search(Query().id == wordID)
response = db.search(where("id") == wordID)

if response:
return response[0]
Expand Down Expand Up @@ -245,22 +242,28 @@ async def get_range_of_words(offset: int = 0, size: int = 5):

@app.get("/api/lookup_word/{word}", response_model=Record)
async def lookup_word_by_string(word: str):
response = db.search(Query().word == word)
response = db.search(where("word") == word)

if response:
return response[0]
raise HTTPException(status_code=404, detail="Word not found lol")
if response:
return response[0]
raise HTTPException(status_code=404, detail="Word not found lol")


@app.get("/api/get_uploaders_posts/{uploader}", response_model=list[Record])
async def get_all_of_a_uploaders_posts(uploader):
return db.search(Query().uploader == uploader.capitalize())
return db.search(where("uploader") == uploader.capitalize())


@app.get("/api/get_all_uploaders", response_model=list[str])
async def get_names_of_all_uploaders():
return list(set([x["uploader"] for x in db.search(Query().uploader.exists())]))
arr = list(set(
[record["uploader"] for record in db.search(where("uploader") != "Unknown")]
))

arr += [record["uploader"] for record in db.search(where("uploader") == "Unknown")]

return arr


@app.get("/api/get_random_word", response_model=RandomWord)
Expand Down
2 changes: 1 addition & 1 deletion frontend/eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import reactPlugin from "eslint-plugin-react";

export default [
{
files: ["*.tsx", "*.ts", "*.jsx", "*.js", "*.cjs"],
files: ["**/*.tsx", "**/*.ts", "**/*.jsx", "**/*.js", "**/*.cjs"],
ignores: ["node_modules/**/*"],
languageOptions: {
parser: tsParser,
Expand Down
10 changes: 5 additions & 5 deletions frontend/src/AddNewWord.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useState } from "react";
import { UploadWord, UploadWordResponse, Word } from "./types";
import { UploadWord, UploadWordError, Word } from "./types";
import { ChevronIcon, createWordDomId } from "./hooks/utils";

type AddNewWordProps = {
Expand Down Expand Up @@ -35,16 +35,16 @@ export default function AddNewWord(props: AddNewWordProps) {
} as UploadWord),
method: "POST",
});
const newWord: UploadWordResponse = await res.json();
const newWord: UploadWordError | Word | string = await res.json();

if("detail" in newWord) {
setErrorMsg(newWord.detail);
if(!res.ok) {
setErrorMsg((newWord as UploadWordError).detail || newWord as string);
return;
}

(e.target as HTMLFormElement).reset();
props.onSubmitFinished?.();
setNewWordDomId(createWordDomId(newWord));
setNewWordDomId(createWordDomId(newWord as Word));
}

return (
Expand Down
1 change: 1 addition & 0 deletions frontend/src/DfnArea.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ export default function DfnArea({ word }: DfnAreaProps) {
return (
<article id={domId} className="dictionary-entry">
<header className="header-section">
<small>Id: {wordData.id}</small>
<h2 className="word">
<dfn aria-details={descriptionDomId}>{wordData.word}</dfn>
</h2>
Expand Down
18 changes: 10 additions & 8 deletions frontend/src/Home.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import { useEffect, useState } from "react";
import AddNewWord from "./AddNewWord";
import DfnArea from "./DfnArea";
import { Word } from "./types";
import { GetAllWordsOrderByOptions, GetAllWordsSortByOptions, Word } from "./types";
import Tooltip from "./components/Tooltip";
import Combobox from "./components/Combobox";

export default function Home() {
const [allWords, setAllWords] = useState<Word[]>([]);
const [isFirstLoading, setFirstIsLoading] = useState(true);
const [isFirstLoading, setIsFirstIsLoading] = useState(true);

useEffect(() => {
(async () => {
await GetAllWords();
setFirstIsLoading(false);
setIsFirstIsLoading(false);
})();
}, []);

Expand All @@ -28,11 +28,13 @@ export default function Home() {
async function GetAllWords() {
const searchParams = new URLSearchParams(location.search);

const json: Word[] = await fetch(
`/api/get_all_words?sortby=${searchParams.get("sortby") || "id"}&orderby=${searchParams.get("orderby") || "asc"}`,
).then(x => x.json());
const sortby = searchParams.get("sortby") as GetAllWordsSortByOptions || "id";
const orderby = searchParams.get("orderby") as GetAllWordsOrderByOptions || "asc";

const json: Word[] = await fetch(`/api/get_all_words?sortby=${sortby}&orderby=${orderby}`).then(x => x.json());

setAllWords(json);
return;
}

return (
Expand Down Expand Up @@ -89,11 +91,11 @@ export default function Home() {
urlKey="orderby"
options={[
{
content: "Ascending",
content: "Ascending (lowest to highest)",
urlValue: "asc",
},
{
content: "Descending",
content: "Descending (highest to lowest)",
urlValue: "desc",
},
]}
Expand Down
17 changes: 10 additions & 7 deletions frontend/src/components/Combobox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ import React, { ReactNode, useEffect, useId, useMemo, useRef, useState } from "r
import { ChevronIcon } from "../hooks/utils";
import { usePopper } from "react-popper";

type OptionUpdate = {
urlKey: string;
urlValue: string;
};

type ComboboxOption = {
content: ReactNode;
urlValue: string;
Expand All @@ -12,7 +17,7 @@ type ComboboxProps = {
urlKey: string;
options: ComboboxOption[];
id?: string;
onUpdate?: (newOption: ComboboxOption) => void;
onUpdate?: (urlKey: string, urlValue: string) => void;
};

export default function Combobox(props: ComboboxProps) {
Expand All @@ -21,9 +26,7 @@ export default function Combobox(props: ComboboxProps) {
), [props.options]);
const [focusedOptionIndex, setFocusedOptionIndex] = useState(intialIndex == -1 ? 0 : intialIndex);
const [confirmedOptionIndex, setConfirmedOptionIndex] = useState(intialIndex == -1 ? 0 : intialIndex);
const comboboxWidth = useMemo(() => (
props.options.toSorted((a, b) => a.content!.toString().length - b.content!.toString().length)[0].toString().length + "ch"
), [props.options]);
const longestWord = useMemo(() => 15, [props.options]);

const [button, setButton] = useState<HTMLButtonElement | null>(null);
const [listbox, setListbox] = useState<HTMLUListElement | null>(null);
Expand Down Expand Up @@ -60,7 +63,7 @@ export default function Combobox(props: ComboboxProps) {
}, [focusedOptionIndex, popper]);

useEffect(() => {
props.onUpdate?.(props.options[confirmedOptionIndex]);
props.onUpdate?.(props.urlKey, props.options[confirmedOptionIndex].urlValue);
}, [confirmedOptionIndex]);

function CreateUrl(urlValue: string, index: number) {
Expand Down Expand Up @@ -109,7 +112,7 @@ export default function Combobox(props: ComboboxProps) {
className="combobox-button"
ref={setButton}
style={{
width: comboboxWidth,
width: `${longestWord}ch`,
}}
//@ts-expect-error The Popover API isn't supported by React or its types yet
popovertarget={listboxId}
Expand All @@ -124,7 +127,7 @@ export default function Combobox(props: ComboboxProps) {
id={listboxId}
style={{
...popper.styles.popper,
width: comboboxWidth,
width: `${longestWord}ch`,
}}
className="listbox"
role="listbox"
Expand Down
11 changes: 6 additions & 5 deletions frontend/src/static_original/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -134,19 +134,20 @@ a:active {
}

.dictionary-entry:target {
border: solid 5px blue;
border: 4px solid #ff9900;
}

.header-section {
color: white;
text-align: center;
background: #3498db;
box-sizing: content-box;
padding: 20px;
}

.word {
font-size: 2.7rem;
font-weight: bold;
padding: 20px;
margin: 0;
color: #1d2a57;
font-family: Arial;
Expand Down Expand Up @@ -261,8 +262,8 @@ a:active {
.definition-section {
margin: 20px;
padding: 5px;
border-top: solid thin #fec400 4px;
border-bottom: solid thin #fec400 4px;
border-top: solid thin #ff9900 4px;
border-bottom: solid thin #ff9900 4px;
white-space: pre;
}

Expand Down Expand Up @@ -460,7 +461,7 @@ output {

.filter-area label {
margin: 0.5rem 0;
display: block;
display: inline-block;
}

.combobox-button {
Expand Down
6 changes: 4 additions & 2 deletions frontend/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export type UploadWord = {
isRobot: boolean;
};

export type UploadWordResponse = Word | {
export type UploadWordError = {
detail: string;
};

Expand All @@ -37,4 +37,6 @@ export type UpdateUpdoot = {
prevUpdootState: UpdootStates;
};

export type GetAllWordsSortByOptions = "totaldoots" | "updoots" | "downdoots" | "id" | "date" | "alphabet";
export type GetAllWordsSortByOptions = "totaldoots" | "updoots" | "downdoots" | "id" | "date" | "alphabet";

export type GetAllWordsOrderByOptions = "asc" | "desc";
1 change: 0 additions & 1 deletion frontend/webpack.config.cjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/* eslint-disable typescript/no-var-requires */
const CopyPlugin = require("copy-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
Expand Down

0 comments on commit 755c6b9

Please sign in to comment.