mirror of
https://github.com/rzmk/learnhouse.git
synced 2025-12-19 04:19:25 +00:00
Merge pull request #73 from learnhouse/swve/eng-21-switch-to-modal-for-course-creation
Switch to modal for course creation
This commit is contained in:
commit
c9ad26782f
4 changed files with 137 additions and 76 deletions
|
|
@ -1,70 +0,0 @@
|
|||
"use client";
|
||||
import { useRouter } from "next/navigation";
|
||||
import React from "react";
|
||||
import { Title } from "@components/UI/Elements/Styles/Title";
|
||||
import { createNewCourse } from "@services/courses/courses";
|
||||
import { getOrganizationContextInfo } from "@services/organizations/orgs";
|
||||
import { getUriWithOrg } from "@services/config/config";
|
||||
|
||||
const NewCoursePage = (params: any) => {
|
||||
const router = useRouter();
|
||||
const orgslug = params.params.orgslug;
|
||||
const [name, setName] = React.useState("");
|
||||
const [description, setDescription] = React.useState("");
|
||||
const [isLoading, setIsLoading] = React.useState(false);
|
||||
const [thumbnail, setThumbnail] = React.useState(null) as any;
|
||||
const [orgId, setOrgId] = React.useState(null) as any;
|
||||
|
||||
|
||||
const getOrgMetadata = async () => {
|
||||
const org = await getOrganizationContextInfo(orgslug);
|
||||
setOrgId(org.org_id);
|
||||
}
|
||||
|
||||
const handleNameChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setName(event.target.value);
|
||||
};
|
||||
|
||||
const handleDescriptionChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setDescription(event.target.value);
|
||||
};
|
||||
|
||||
const handleThumbnailChange = (event: React.ChangeEvent<any>) => {
|
||||
setThumbnail(event.target.files[0]);
|
||||
};
|
||||
|
||||
const handleSubmit = async (e: any) => {
|
||||
e.preventDefault();
|
||||
let status = await createNewCourse(orgId, { name, description }, thumbnail);
|
||||
|
||||
// TODO : wow this is terrible - fix this
|
||||
if (status.org_id == orgId) {
|
||||
router.push(getUriWithOrg(orgslug, `/courses`));
|
||||
} else {
|
||||
alert("Error creating course, please see console logs");
|
||||
console.log(status);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
React.useEffect(() => {
|
||||
if (orgslug) {
|
||||
getOrgMetadata();
|
||||
}
|
||||
}, [isLoading, orgslug]);
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<Title>New Course </Title>
|
||||
<hr />
|
||||
Name : <input onChange={handleNameChange} type="text" /> <br />
|
||||
Description : <input onChange={handleDescriptionChange} type="text" /> <br />
|
||||
Cover Photo : <input onChange={handleThumbnailChange} type="file" /> <br />
|
||||
Learnings (empty for now) (separated by ; ) : <textarea id="story" name="story" rows={5} cols={33} /> <br />
|
||||
<button onClick={handleSubmit}>Create</button>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default NewCoursePage;
|
||||
|
|
@ -9,10 +9,13 @@ import { deleteCourseFromBackend } from "@services/courses/courses";
|
|||
import useSWR, { mutate } from "swr";
|
||||
import { swrFetcher } from "@services/utils/ts/requests";
|
||||
import { Edit2, Trash } from "lucide-react";
|
||||
import Modal from "@components/UI/Modal/Modal";
|
||||
import CreateCourseModal from "@components/Pages/CreateCourse/CreateCourse";
|
||||
|
||||
const CoursesIndexPage = (params: any) => {
|
||||
const router = useRouter();
|
||||
const orgslug = params.params.orgslug;
|
||||
const [newCourseModal, setNewCourseModal] = React.useState(false);
|
||||
|
||||
const { data: courses, error: error } = useSWR(`${getAPIUrl()}courses/org_slug/${orgslug}/page/1/limit/10`, swrFetcher);
|
||||
|
||||
|
|
@ -21,6 +24,10 @@ const CoursesIndexPage = (params: any) => {
|
|||
mutate(`${getAPIUrl()}courses/org_slug/${orgslug}/page/1/limit/10`);
|
||||
}
|
||||
|
||||
async function closeNewCourseModal() {
|
||||
setNewCourseModal(false);
|
||||
}
|
||||
|
||||
// function to remove "course_" from the course_id
|
||||
function removeCoursePrefix(course_id: string) {
|
||||
return course_id.replace("course_", "");
|
||||
|
|
@ -29,10 +36,22 @@ const CoursesIndexPage = (params: any) => {
|
|||
return (
|
||||
<>
|
||||
<Title>
|
||||
Courses :{" "}
|
||||
<Link href={getUriWithOrg(orgslug, "/courses/new")}>
|
||||
<button>+</button>
|
||||
</Link>{" "}
|
||||
Courses {" "}
|
||||
<Modal
|
||||
isDialogOpen={newCourseModal}
|
||||
onOpenChange={setNewCourseModal}
|
||||
minHeight="md"
|
||||
dialogContent={<CreateCourseModal
|
||||
closeModal={closeNewCourseModal}
|
||||
orgslug={orgslug}
|
||||
></CreateCourseModal>}
|
||||
dialogTitle="Create Course"
|
||||
dialogDescription="Create a new course"
|
||||
dialogTrigger={
|
||||
<button> Add Course +
|
||||
</button>
|
||||
}
|
||||
/>
|
||||
</Title>
|
||||
{error && <p>Failed to load</p>}
|
||||
{!courses ? (
|
||||
|
|
|
|||
112
front/components/Pages/CreateCourse/CreateCourse.tsx
Normal file
112
front/components/Pages/CreateCourse/CreateCourse.tsx
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
import FormLayout, { ButtonBlack, Flex, FormField, FormLabel, Input, Textarea } from '@components/UI/Form/Form'
|
||||
import * as Form from '@radix-ui/react-form'
|
||||
import { getAPIUrl, getUriWithOrg } from '@services/config/config';
|
||||
import { FormMessage } from "@radix-ui/react-form";
|
||||
import { createNewCourse } from '@services/courses/courses';
|
||||
import { getOrganizationContextInfo } from '@services/organizations/orgs';
|
||||
import React, { useState } from 'react'
|
||||
import { BarLoader } from 'react-spinners'
|
||||
import { mutate } from 'swr';
|
||||
|
||||
function CreateCourseModal({ closeModal, orgslug }: any) {
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
const [name, setName] = React.useState("");
|
||||
const [description, setDescription] = React.useState("");
|
||||
const [isLoading, setIsLoading] = React.useState(false);
|
||||
const [thumbnail, setThumbnail] = React.useState(null) as any;
|
||||
|
||||
const [orgId, setOrgId] = React.useState(null) as any;
|
||||
|
||||
|
||||
const getOrgMetadata = async () => {
|
||||
const org = await getOrganizationContextInfo(orgslug);
|
||||
setOrgId(org.org_id);
|
||||
}
|
||||
|
||||
|
||||
const handleNameChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setName(event.target.value);
|
||||
};
|
||||
|
||||
const handleDescriptionChange = (event: React.ChangeEvent<any>) => {
|
||||
setDescription(event.target.value);
|
||||
};
|
||||
|
||||
const handleThumbnailChange = (event: React.ChangeEvent<any>) => {
|
||||
setThumbnail(event.target.files[0]);
|
||||
};
|
||||
|
||||
const handleSubmit = async (e: any) => {
|
||||
e.preventDefault();
|
||||
setIsSubmitting(true);
|
||||
let status = await createNewCourse(orgId, { name, description }, thumbnail);
|
||||
mutate(`${getAPIUrl()}courses/org_slug/${orgslug}/page/1/limit/10`);
|
||||
setIsSubmitting(false);
|
||||
|
||||
if (status.org_id == orgId) {
|
||||
closeModal();
|
||||
} else {
|
||||
alert("Error creating course, please see console logs");
|
||||
console.log(status);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
React.useEffect(() => {
|
||||
if (orgslug) {
|
||||
getOrgMetadata();
|
||||
}
|
||||
}, [isLoading, orgslug]);
|
||||
|
||||
return (
|
||||
<FormLayout onSubmit={handleSubmit}>
|
||||
<FormField name="course-name">
|
||||
<Flex css={{ alignItems: 'baseline', justifyContent: 'space-between' }}>
|
||||
<FormLabel>Course name</FormLabel>
|
||||
<FormMessage match="valueMissing">Please provide a course name</FormMessage>
|
||||
</Flex>
|
||||
<Form.Control asChild>
|
||||
<Input onChange={handleNameChange} type="text" required />
|
||||
</Form.Control>
|
||||
</FormField>
|
||||
<FormField name="course-desc">
|
||||
<Flex css={{ alignItems: 'baseline', justifyContent: 'space-between' }}>
|
||||
<FormLabel>Course description</FormLabel>
|
||||
<FormMessage match="valueMissing">Please provide a course description</FormMessage>
|
||||
</Flex>
|
||||
<Form.Control asChild>
|
||||
<Textarea onChange={handleDescriptionChange} required />
|
||||
</Form.Control>
|
||||
</FormField>
|
||||
<FormField name="course-thumbnail">
|
||||
<Flex css={{ alignItems: 'baseline', justifyContent: 'space-between' }}>
|
||||
<FormLabel>Course thumbnail</FormLabel>
|
||||
<FormMessage match="valueMissing">Please provide a thumbnail for your course</FormMessage>
|
||||
</Flex>
|
||||
<Form.Control asChild>
|
||||
<Input onChange={handleThumbnailChange} type="file" required />
|
||||
</Form.Control>
|
||||
</FormField>
|
||||
<FormField name="course-learnings">
|
||||
<Flex css={{ alignItems: 'baseline', justifyContent: 'space-between' }}>
|
||||
<FormLabel>Course Learnings</FormLabel>
|
||||
<FormMessage match="valueMissing">Please provide learning elements, separated by comma (,)</FormMessage>
|
||||
</Flex>
|
||||
<Form.Control asChild>
|
||||
<Textarea required />
|
||||
</Form.Control>
|
||||
</FormField>
|
||||
|
||||
<Flex css={{ marginTop: 25, justifyContent: 'flex-end' }}>
|
||||
<Form.Submit asChild>
|
||||
<ButtonBlack type="submit" css={{ marginTop: 10 }}>
|
||||
{isSubmitting ? <BarLoader cssOverride={{ borderRadius: 60, }} width={60} color="#ffffff" />
|
||||
: "Create Course"}
|
||||
</ButtonBlack>
|
||||
</Form.Submit>
|
||||
</Flex>
|
||||
</FormLayout>
|
||||
)
|
||||
}
|
||||
|
||||
export default CreateCourseModal
|
||||
|
|
@ -27,7 +27,7 @@ export const Menu = (props : any ) => {
|
|||
<SearchArea>
|
||||
<Search>
|
||||
<ToolTip content={<div>
|
||||
<p>{process.env.VERCEL_GIT_COMMIT_SHA}</p>
|
||||
<p>{process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA}</p>
|
||||
</div>}><PreAlphaLabel>pre-alpha</PreAlphaLabel></ToolTip>
|
||||
</Search>
|
||||
</SearchArea>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue