feat: submit announcement posts

This commit is contained in:
2024-11-15 19:09:54 +01:00
parent 39e0a26610
commit bf2fc44aee
7 changed files with 123 additions and 24 deletions

5
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,5 @@
{
"editor.tabSize": 2,
"editor.insertSpaces": true,
"editor.detectIndentation": false
}

View File

@@ -35,6 +35,13 @@ const DrawerLayout = () => {
title: 'Courses',
}}
/>
<Drawer.Screen
name="courses/announcement/create/[id]"
options={{
drawerLabel: 'Create Announcement',
title: 'Create Announcement',
}}
/>
</Drawer>
</GestureHandlerRootView>
)

View File

@@ -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() {
}}
>
<Surface className="flex-1">
<AddAnnouncement />
<Text>hi this is class with name {course?.name}</Text>
<CourseBoard />
</Surface>

View File

@@ -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 (
<Surface className="flex-1">
<TextInput
label="Announcement"
multiline
numberOfLines={4}
value={text}
onChangeText={setText}
/>
<Button
onPress={() => {
postAnnouncement(text, {
onSuccess: () => {
ToastAndroid.show('Announcement posted', ToastAndroid.SHORT)
router.push(`/drawer/courses/${id}`)
},
})
}}
loading={isPending}
>
Submit
</Button>
</Surface>
)
}

View File

@@ -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,

View File

@@ -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 (
<View className="m-2.5">
<Pressable
onPress={() => router.push(`/drawer/courses/announcement/create/${id}`)}
>
<Card className="border border-gray-200 dark:border-gray-700">
<Card.Title
title="Create a new announcement"
left={(iP) => <Avatar.Icon {...iP} icon="plus" />}
/>
</Card>
</Pressable>
</View>
)
}

View File

@@ -15,9 +15,9 @@ export default function CourseBoard() {
const { id } = useLocalSearchParams() as { id: string }
const [organizedData, setOrganizedData] = useState<JSX.Element[]>([])
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])
// 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) {
return <Loading />
setOrganizedData([<Loading key="loading" />])
}
}, [annIsLoading, cwIsLoading, cwmIsLoading])
return (
<Surface className="flex-1">
{/* <Text>Announcements</Text>
{announcement?.map((a) => <Announcement key={a.id} {...a} />)}
<Text>Course Work</Text>
{courseWork &&
courseWork.map((cw) => (
<CourseWorkCard key={cw.id} isCWM={false} data={cw} />
))}
<Text>Course Work Material</Text>
{courseWorkMaterial &&
courseWorkMaterial.map((cwm) => (
<CourseWorkCard key={cwm.id} isCWM data={cwm} />
))} */}
{organizedData}
</Surface>
)
return <Surface className="flex-1">{organizedData}</Surface>
}