Skip to content

Commit

Permalink
feat: move queries and mutations to own files
Browse files Browse the repository at this point in the history
  • Loading branch information
bchmnn committed Jul 14, 2024
1 parent c1dbdcb commit 3d466bd
Show file tree
Hide file tree
Showing 25 changed files with 411 additions and 248 deletions.
21 changes: 3 additions & 18 deletions service/frontend/src/app/login/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,11 @@

import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";
import { navigate } from "@/actions/navigate";
import { Button } from "@/components/ui/button";
import axios from "axios";
import { z } from "zod";
import { Form, FormControl, FormField, FormItem, FormMessage } from "@/components/ui/form";
import { Input } from "@/components/ui/input";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { useLoginMutation } from "@/hooks/use-login-mutation";

const LoginFormSchema = z.object({
username: z.string().min(1, { message: "Username can't be empty" }),
Expand All @@ -18,8 +16,6 @@ const LoginFormSchema = z.object({
type LoginForm = z.infer<typeof LoginFormSchema>;

export default function Page() {
const queryClient = useQueryClient();

const form = useForm<LoginForm>({
resolver: zodResolver(LoginFormSchema),
defaultValues: {
Expand All @@ -28,18 +24,7 @@ export default function Page() {
}
})

const mutation = useMutation({
mutationFn: (credentials: LoginForm) => axios.post(
(process.env.NEXT_PUBLIC_API ?? "") + '/api/auth/login',
credentials,
{
withCredentials: true
}
),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['user'] })
navigate("/")
},
const loginMutation = useLoginMutation({
onError: () => {
form.setError("password", {
message: "Password is wrong"
Expand All @@ -48,7 +33,7 @@ export default function Page() {
})

const onSubmit = (credentials: LoginForm) => {
mutation.mutate(credentials);
loginMutation.mutate(credentials);
}

return (
Expand Down
19 changes: 3 additions & 16 deletions service/frontend/src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,12 @@
import CreateDevenvButton from "@/components/create-devenv-button";
import CreateReplButton from "@/components/create-repl-button";
import { Button } from "@/components/ui/button";
import { GetUserResponse } from "@/lib/types";
import { useUserQuery } from "@/hooks/use-user-query";
import { RocketIcon } from "@radix-ui/react-icons"
import { useQuery } from "@tanstack/react-query";
import axios from "axios";

export default function Page() {
const query = useQuery({
queryKey: ['user'],
queryFn: () => axios.get<GetUserResponse>(
(process.env.NEXT_PUBLIC_API ?? "") + "/api/auth/user",
{
withCredentials: true
}
),
staleTime: Infinity,
})


const isAuthenticatedMode = !query.isStale && query.isSuccess
const userQuery = useUserQuery()
const isAuthenticatedMode = !userQuery.isStale && userQuery.isSuccess

return (
<main className="flex h-screen w-screen flex-col items-center p-24 justify-center space-y-5">
Expand Down
16 changes: 2 additions & 14 deletions service/frontend/src/app/register/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,11 @@

import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";
import { navigate } from "@/actions/navigate";
import { Button } from "@/components/ui/button";
import axios from "axios";
import { z } from "zod";
import { Form, FormControl, FormField, FormItem, FormMessage } from "@/components/ui/form";
import { Input } from "@/components/ui/input";
import { useMutation } from "@tanstack/react-query";
import { useRegisterMutation } from "@/hooks/use-register-mutation";

const RegisterFormSchema = z.object({
username: z.string().min(4, { message: "Minimum length 4" }).max(64, { message: "Maximum length 4" }).regex(/^[a-zA-Z0-9]*$/, { message: "Only alphanumeric" }),
Expand All @@ -27,17 +25,7 @@ export default function Page() {
}
})

const mutation = useMutation({
mutationFn: (credentials: RegisterForm) => axios.post(
(process.env.NEXT_PUBLIC_API ?? "") + '/api/auth/register',
credentials,
{
withCredentials: true
}
),
onSuccess: () => {
navigate("/login")
},
const mutation = useRegisterMutation({
onError: () => {
form.setError("username", {
message: "That did not work, user exists?"
Expand Down
30 changes: 7 additions & 23 deletions service/frontend/src/components/create-devenv-button.tsx
Original file line number Diff line number Diff line change
@@ -1,35 +1,18 @@
"use client";

import { navigate } from "@/actions/navigate";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import axios from "axios";
import { Button, ButtonProps } from "./ui/button";
import { CodeIcon, ReloadIcon } from "@radix-ui/react-icons";
import React from "react";
import { CreateDevenvRequest, CreateDevenvResponse } from "@/lib/types";
import { randomString } from "@/lib/utils";
import { useCreateDevenvMutation } from "@/hooks/use-create-devenv-mutation";

const CreateDevenvButton = React.forwardRef<HTMLButtonElement, ButtonProps>(
(props, ref) => {
const client = useQueryClient();
const createDevenvMutation = useCreateDevenvMutation();

const mutation = useMutation({
mutationFn: (credentials: CreateDevenvRequest) => axios.post<CreateDevenvResponse>(
(process.env.NEXT_PUBLIC_API ?? "") + '/api/devenv',
credentials,
{
withCredentials: true
}
),
onSuccess: (response) => {
client.invalidateQueries({ queryKey: ['devenvs'] })
navigate("/devenv/" + response.data.devenvUuid)
},
})

const handleCreateRepl = (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
const handleCreateDevenv = (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
const name = randomString(10);
mutation.mutate({
createDevenvMutation.mutate({
name,
buildCmd: "gcc -o main main.c",
runCmd: "./main"
Expand All @@ -38,8 +21,8 @@ const CreateDevenvButton = React.forwardRef<HTMLButtonElement, ButtonProps>(
}

return (
<Button ref={ref} {...props} disabled={mutation.isPending} onClick={handleCreateRepl}>
{mutation.isPending ? <ReloadIcon className="mr-2 h-4 w-4 animate-spin" /> :
<Button ref={ref} {...props} disabled={createDevenvMutation.isPending} onClick={handleCreateDevenv}>
{createDevenvMutation.isPending ? <ReloadIcon className="mr-2 h-4 w-4 animate-spin" /> :
<CodeIcon className="mr-2 h-4 w-4" />} DEVENVME!
</Button>
)
Expand All @@ -49,3 +32,4 @@ const CreateDevenvButton = React.forwardRef<HTMLButtonElement, ButtonProps>(
CreateDevenvButton.displayName = "CreateDevenvButton";

export default CreateDevenvButton;

35 changes: 6 additions & 29 deletions service/frontend/src/components/create-repl-button.tsx
Original file line number Diff line number Diff line change
@@ -1,53 +1,30 @@
"use client";

import { navigate } from "@/actions/navigate";
import { randomString } from "@/lib/utils";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import axios from "axios";
import { Button, ButtonProps } from "./ui/button";
import { ReloadIcon } from "@radix-ui/react-icons";
import React from "react";
import { PiTerminalWindowLight } from "react-icons/pi";

type Credentials = {
username: string,
password: string,
}
import { useCreateReplMutation } from "@/hooks/use-create-repl-mutation";

const CreateReplButton = React.forwardRef<HTMLButtonElement, ButtonProps>(
(props, ref) => {
const client = useQueryClient();

const mutation = useMutation({
mutationFn: (credentials: Credentials) => axios.post<{ id: string }>(
(process.env.NEXT_PUBLIC_API ?? "") + '/api/repl',
credentials,
{
withCredentials: true
}
),
onSuccess: (response) => {
client.invalidateQueries({ queryKey: ['repl-sessions'] })
navigate("/repl/" + response.data.id)
},
})

const createReplMutation = useCreateReplMutation()
const handleCreateRepl = (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
const username = randomString(60);
const password = randomString(60);
mutation.mutate({ username, password });
createReplMutation.mutate({ username, password });
if (props.onClick) props.onClick(event)
}

return (
<Button ref={ref} {...props} disabled={mutation.isPending} onClick={handleCreateRepl}>
{mutation.isPending ? <ReloadIcon className="mr-2 h-4 w-4 animate-spin" /> :
<Button ref={ref} {...props} disabled={createReplMutation.isPending} onClick={handleCreateRepl}>
{createReplMutation.isPending ? <ReloadIcon className="mr-2 h-4 w-4 animate-spin" /> :
<PiTerminalWindowLight className="mr-2 h-4 w-4" />} REPLME!
</Button>
)
}
)

CreateReplButton.displayName = "CreateReplButton";

export default CreateReplButton;

16 changes: 4 additions & 12 deletions service/frontend/src/components/devenv-menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,14 @@ import {
DrawerTitle,
DrawerTrigger,
} from "@/components/ui/drawer"
import { useQuery } from "@tanstack/react-query";
import axios from "axios";
import { CodeIcon } from "@radix-ui/react-icons";
import { navigate } from "@/actions/navigate";
import { Devenv } from "@/lib/types";
import CreateDevenvButton from "./create-devenv-button";
import { useDevenvsQuery } from "@/hooks/use-devenvs-query";

const DevenvMenu = () => {
const query = useQuery(
{
queryKey: ["devenvs"],
queryFn: () => axios.get<Devenv[]>((process.env.NEXT_PUBLIC_API ?? "") + '/api/devenv', { withCredentials: true }),
}
)

const numSessions = query.data?.data?.length ?? 0;
const devenvsQuery = useDevenvsQuery();
const numSessions = devenvsQuery.data?.data?.length ?? 0;

return (
<Drawer>
Expand All @@ -43,7 +35,7 @@ const DevenvMenu = () => {
</DrawerHeader>

<div className="flex flex-row justify-center items-center w-full space-x-5 overflow-auto">
{query.data?.data?.map((devenv) => (
{devenvsQuery.data?.data?.map((devenv) => (
<DrawerClose asChild key={devenv.id}>
<Button variant="outline" onClick={() => navigate("/devenv/" + devenv.id)}>
{devenv.name}
Expand Down
39 changes: 8 additions & 31 deletions service/frontend/src/components/editor.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
"use client";

import { useDevenvFileContentQuery } from '@/hooks/use-devenv-file-content-query';
import { useDevenvFileContentMutation } from '@/hooks/use-devenv-file-content-mutation';
import MonacoEditor, { Monaco, OnChange } from '@monaco-editor/react';
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import axios from 'axios';
import { useTheme } from 'next-themes';

type EditorProps = {
Expand All @@ -13,41 +13,18 @@ type EditorProps = {

const Editor: React.FC<EditorProps> = (props) => {
const { className, devenvUuid, filename } = props;
const queryClient = useQueryClient();

const { resolvedTheme } = useTheme();
const editorTheme = resolvedTheme === "light" ? "light" : "dark";

const fileContentQuery = useQuery({
queryKey: ['devenv', devenvUuid, 'files', filename, 'content'],
queryFn: () => axios.get<string>(
(process.env.NEXT_PUBLIC_API ?? "") + "/api/devenv/" + devenvUuid + "/files/" + filename,
{
withCredentials: true
}
).then((data) => {
return data.data
}),
staleTime: Infinity,
enabled: Boolean(filename)
const fileContentQuery = useDevenvFileContentQuery({
uuid: devenvUuid,
filename
})

const fileContentMutation = useMutation({
mutationFn: (value: string) => axios.post(
(process.env.NEXT_PUBLIC_API ?? "") + "/api/devenv/" + devenvUuid + "/files/" + filename,
value,
{
withCredentials: true
}
),
onSuccess: (_, value) => {
queryClient.setQueryData<string>(
['devenv', devenvUuid, 'files', filename, 'content'],
() => {
return value
}
)
},
const fileContentMutation = useDevenvFileContentMutation({
uuid: devenvUuid,
filename
})

const handleEditorWillMount = (monaco: Monaco) => {
Expand Down
Loading

0 comments on commit 3d466bd

Please sign in to comment.