diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..67d749a --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "editor.tabSize": 2, + "editor.insertSpaces": true, + "editor.detectIndentation": false +} \ No newline at end of file diff --git a/app/(app)/drawer/_layout.tsx b/app/(app)/drawer/_layout.tsx index e0b8e30..210c9a0 100644 --- a/app/(app)/drawer/_layout.tsx +++ b/app/(app)/drawer/_layout.tsx @@ -35,6 +35,13 @@ const DrawerLayout = () => { title: 'Courses', }} /> + ) diff --git a/app/(app)/drawer/courses/[id].tsx b/app/(app)/drawer/courses/[id].tsx index 27645a9..50186b2 100644 --- a/app/(app)/drawer/courses/[id].tsx +++ b/app/(app)/drawer/courses/[id].tsx @@ -3,6 +3,7 @@ import { ScrollView } from 'react-native' import { Surface, Text, useTheme } from 'react-native-paper' import { useCourse } from '@/lib/clients/classroom' +import AddAnnouncement from '@/lib/ui/components/AddAnnouncement' import CourseBoard from '@/lib/ui/components/CourseBoard' import Loading from '@/lib/ui/components/Loading' @@ -24,6 +25,7 @@ export default function Courses() { }} > + hi this is class with name {course?.name} diff --git a/app/(app)/drawer/courses/announcement/create/[id].tsx b/app/(app)/drawer/courses/announcement/create/[id].tsx new file mode 100644 index 0000000..c4dcd2d --- /dev/null +++ b/app/(app)/drawer/courses/announcement/create/[id].tsx @@ -0,0 +1,37 @@ +import { usePostAnnouncement } from '@/lib/clients/classroom' +import { useLocalSearchParams, useRouter } from 'expo-router' +import { useState } from 'react' +import { ToastAndroid } from 'react-native' +import { Button, Surface, TextInput } from 'react-native-paper' + +export default function Page() { + const { id } = useLocalSearchParams() as { id: string } + const { mutate: postAnnouncement, isPending } = usePostAnnouncement(id) + const [text, setText] = useState('') + const router = useRouter() + + return ( + + + + + ) +} diff --git a/lib/clients/classroom.ts b/lib/clients/classroom.ts index ca89f8f..07e0472 100644 --- a/lib/clients/classroom.ts +++ b/lib/clients/classroom.ts @@ -1,7 +1,7 @@ /* eslint-disable no-throw-literal */ import { type classroom_v1 } from '@googleapis/classroom' import { GoogleSignin } from '@react-native-google-signin/google-signin' -import { QueryClient, useQuery } from '@tanstack/react-query' +import { QueryClient, useMutation, useQuery } from '@tanstack/react-query' import { AnnouncementUserProfile } from '../types/Classroom' @@ -162,6 +162,43 @@ export function useCourseWorkMaterials(courseId: string) { }) } +async function postAnnouncement(courseId: string, text: string) { + const token = await getAuthToken() + const response = await fetch( + `${BASE_URL}/v1/courses/${courseId}/announcements`, + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}`, + }, + body: JSON.stringify({ + text, + state: 'PUBLISHED', + }), + }, + ) + + if (!response.ok) { + throw { message: response.statusText, status: response.status } as ApiError + } + + return response.json() +} + +// Mutation hook +export function usePostAnnouncement(courseId: string) { + return useMutation({ + mutationFn: (text: string) => postAnnouncement(courseId, text), + onSuccess: () => { + // Invalidate announcements query to refetch + queryClient.invalidateQueries({ + queryKey: keys.courses.announcements(courseId), + }) + }, + }) +} + // various api utils from now on export function classroomDateTimeToISO( date: classroom_v1.Schema$Date, diff --git a/lib/ui/components/AddAnnouncement.tsx b/lib/ui/components/AddAnnouncement.tsx new file mode 100644 index 0000000..df51194 --- /dev/null +++ b/lib/ui/components/AddAnnouncement.tsx @@ -0,0 +1,23 @@ +import { useLocalSearchParams, useRouter } from 'expo-router' +import { View, Pressable } from 'react-native' +import { Card, Avatar } from 'react-native-paper' + +export default function AddAnnouncement() { + const { id } = useLocalSearchParams() as { id: string } + const router = useRouter() + + return ( + + router.push(`/drawer/courses/announcement/create/${id}`)} + > + + } + /> + + + + ) +} diff --git a/lib/ui/components/CourseBoard.tsx b/lib/ui/components/CourseBoard.tsx index b53989b..c43a51d 100644 --- a/lib/ui/components/CourseBoard.tsx +++ b/lib/ui/components/CourseBoard.tsx @@ -15,9 +15,9 @@ export default function CourseBoard() { const { id } = useLocalSearchParams() as { id: string } const [organizedData, setOrganizedData] = useState([]) - const { data: announcement, isLoading: annIsLoading } = useAnnouncements(id) - const { data: courseWork, isLoading: cwIsLoading } = useCourseWork(id) - const { data: courseWorkMaterial, isLoading: cwmIsLoading } = + const { data: announcement, isFetching: annIsLoading } = useAnnouncements(id) + const { data: courseWork, isFetching: cwIsLoading } = useCourseWork(id) + const { data: courseWorkMaterial, isFetching: cwmIsLoading } = useCourseWorkMaterials(id) useEffect(() => { @@ -74,25 +74,13 @@ export default function CourseBoard() { // eslint-disable-next-line react-hooks/exhaustive-deps }, [announcement, courseWork, courseWorkMaterial]) - if (annIsLoading || cwIsLoading || cwmIsLoading) { - return - } + // TODO: THIS DOESNT WORK RAHH SEND HELP + // inside a useeffect to make the loading spinner appear when adding a new announcement for example + useEffect(() => { + if (annIsLoading || cwIsLoading || cwmIsLoading) { + setOrganizedData([]) + } + }, [annIsLoading, cwIsLoading, cwmIsLoading]) - return ( - - {/* Announcements - {announcement?.map((a) => )} - Course Work - {courseWork && - courseWork.map((cw) => ( - - ))} - Course Work Material - {courseWorkMaterial && - courseWorkMaterial.map((cwm) => ( - - ))} */} - {organizedData} - - ) + return {organizedData} }