pages_classroom.tsx 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. import React, { useState, useEffect } from 'react';
  2. import { useAuth } from './hooks.tsx';
  3. import { useNavigate, useSearchParams } from 'react-router';
  4. import { Role, ClassStatus } from './components/Classroom/useClassroom.ts';
  5. // import { TeacherView } from './components/Classroom/TeacherView.tsx';
  6. // import { StudentView } from './components/Classroom/StudentView.tsx';
  7. import { ClassroomLayout } from './components/Classroom/ClassroomLayout.tsx';
  8. import { AuthLayout } from './components/Classroom/AuthLayout.tsx';
  9. import { ClassroomProvider, useClassroomContext } from "./components/Classroom/ClassroomProvider.tsx";
  10. import { ToastContainer } from 'react-toastify';
  11. const RoleSelection = () => {
  12. const { setRole, login } = useClassroomContext();
  13. const chooseRole = (role: Role) => {
  14. setRole(role);
  15. login(role);
  16. }
  17. return (
  18. <div className="flex flex-col items-center justify-center h-full">
  19. <h2 className="text-2xl font-bold mb-8">请选择您的角色</h2>
  20. <div className="flex space-x-4">
  21. <button
  22. type="button"
  23. onClick={() => chooseRole(Role.Teacher)}
  24. className="px-6 py-3 bg-blue-500 text-white rounded-lg hover:bg-blue-600 transition-colors"
  25. >
  26. 我是老师
  27. </button>
  28. <button
  29. type="button"
  30. onClick={() => chooseRole(Role.Student)}
  31. className="px-6 py-3 bg-green-500 text-white rounded-lg hover:bg-green-600 transition-colors"
  32. >
  33. 我是学生
  34. </button>
  35. </div>
  36. </div>
  37. );
  38. };
  39. const JoinClassSection = () => {
  40. const { joinClass } = useClassroomContext();
  41. const [classId, setClassId] = useState('');
  42. const handleJoinClass = async () => {
  43. if (!classId.trim()) return;
  44. await joinClass(classId);
  45. };
  46. return (
  47. <div className="bg-white p-4 rounded shadow mb-4">
  48. <h3 className="font-bold mb-2">加入课堂</h3>
  49. <div className="flex space-x-2">
  50. <input
  51. type="text"
  52. value={classId}
  53. onChange={(e) => setClassId(e.target.value)}
  54. placeholder="输入课堂ID"
  55. className="flex-1 px-3 py-2 border rounded"
  56. />
  57. <button
  58. type="button"
  59. onClick={handleJoinClass}
  60. className="px-4 py-2 bg-blue-500 text-white rounded"
  61. >
  62. 加入课堂
  63. </button>
  64. </div>
  65. </div>
  66. );
  67. };
  68. const CreateClassSection = () => {
  69. const { classStatus, createClass, className, setClassName, role } = useClassroomContext();
  70. const navigate = useNavigate();
  71. const handleCreateClass = async () => {
  72. if (!className.trim()) return;
  73. const classId = await createClass(className);
  74. if (classId) {
  75. navigate(`/mobile/classroom/${classId}/${role === Role.Teacher ? Role.Teacher : Role.Student}`, { replace: true });
  76. }
  77. };
  78. if (classStatus !== ClassStatus.NOT_STARTED) return null;
  79. return (
  80. <div className="bg-white p-4 rounded shadow mb-4">
  81. <h3 className="font-bold mb-2">创建新课堂</h3>
  82. <div className="flex space-x-2">
  83. <input
  84. type="text"
  85. value={className}
  86. onChange={(e) => setClassName(e.target.value)}
  87. placeholder="输入课堂名称"
  88. className="flex-1 px-3 py-2 border rounded"
  89. />
  90. <button
  91. type="button"
  92. onClick={handleCreateClass}
  93. className="px-4 py-2 bg-green-500 text-white rounded"
  94. >
  95. 创建课堂
  96. </button>
  97. </div>
  98. </div>
  99. );
  100. };
  101. const Classroom = () => {
  102. const context = useClassroomContext();
  103. const { role, classStatus, isLoggedIn, login, classId, joinClass, setRole } = context;
  104. const [searchParams] = useSearchParams();
  105. useEffect(() => {
  106. // 处理URL中的role参数
  107. const urlRole = searchParams.get('role');
  108. if (urlRole && !role) {
  109. const roleValue = urlRole === 'admin' ? Role.Teacher : Role.Student;
  110. setRole(roleValue);
  111. login(roleValue);
  112. }
  113. }, [searchParams]);
  114. useEffect(() => {
  115. if (!isLoggedIn && role && classId) {
  116. (async () => {
  117. await login(role);
  118. await joinClass(classId);
  119. })()
  120. }
  121. }, [isLoggedIn, role , classId]);
  122. if (!role) {
  123. return (
  124. <AuthLayout>
  125. <RoleSelection />
  126. </AuthLayout>
  127. );
  128. }
  129. if (!isLoggedIn) {
  130. return (
  131. <AuthLayout>
  132. <div className="flex items-center justify-center h-full">
  133. <p>正在自动登录中...</p>
  134. </div>
  135. </AuthLayout>
  136. );
  137. }
  138. if (role === Role.Teacher && !context.isJoinedClass && !classId) {
  139. return (
  140. <>
  141. <AuthLayout>
  142. <CreateClassSection />
  143. </AuthLayout>
  144. </>
  145. );
  146. }
  147. if (role === Role.Student && !context.isJoinedClass && !classId) {
  148. return (
  149. <>
  150. <AuthLayout>
  151. <JoinClassSection />
  152. </AuthLayout>
  153. </>
  154. );
  155. }
  156. if (classStatus === ClassStatus.ENDED) {
  157. return (
  158. <div className="text-center py-8">
  159. <h2 className="text-xl font-bold">课堂已结束</h2>
  160. <p>感谢参与本次课堂</p>
  161. </div>
  162. );
  163. }
  164. return (
  165. <ClassroomLayout role={role}>
  166. {/* {role === Role.Teacher ? <TeacherView /> : <StudentView />} */}
  167. <></>
  168. </ClassroomLayout>
  169. );
  170. };
  171. export const ClassroomPage = () => {
  172. const { user } = useAuth();
  173. return (
  174. <>
  175. <ClassroomProvider user={user!}>
  176. <Classroom />
  177. </ClassroomProvider>
  178. <ToastContainer
  179. position="top-right"
  180. autoClose={500}
  181. hideProgressBar={false}
  182. newestOnTop={false}
  183. closeOnClick
  184. rtl={false}
  185. pauseOnFocusLoss
  186. draggable
  187. pauseOnHover
  188. />
  189. </>
  190. )
  191. }