Skip to content
This repository has been archived by the owner on Sep 25, 2023. It is now read-only.

Commit

Permalink
Merge pull request #48 from soulsam480/student-views/feat/basics-scor…
Browse files Browse the repository at this point in the history
…e-education

Student views/feat/basics score education
  • Loading branch information
soulsam480 authored May 26, 2022
2 parents e3c744d + 0307f12 commit f70419e
Show file tree
Hide file tree
Showing 52 changed files with 2,352 additions and 946 deletions.
19 changes: 16 additions & 3 deletions .eslintrc-auto-import.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,35 @@
"globals": {
"IconLaBars": true,
"IconLaBook": true,
"IconLaBookReader": true,
"IconLaBuilding": true,
"IconLaCalendar": true,
"IconLaCheckCircleSolid": true,
"IconLaChevronDown": true,
"IconLaExclamationCircle": true,
"IconLaExclamationTriangle": true,
"IconLaFileAltSolid": true,
"IconLaFlask": true,
"IconLaGraduationCap": true,
"IconLaHandsHelping": true,
"IconLaHome": true,
"IconLaHotel": true,
"IconLaIdCardSolid": true,
"IconLaMailBulk": true,
"IconLaMoneyBill": true,
"IconLaMoon": true,
"IconLaPassport": true,
"IconLaPenSquare": true,
"IconLaPlusCircle": true,
"IconLaRocket": true,
"IconLaRulerCombined": true,
"IconLaSchool": true,
"IconLaShieldAlt": true,
"IconLaSitemap": true,
"IconLaSortAmountDown": true,
"IconLaSortAmountUp": true,
"IconLaSun": true,
"IconLaTicketAlt": true,
"IconLaTimes": true,
"IconLaTimesCircle": true,
"IconLaTrashAltSolid": true,
"IconLaUndoAlt": true,
"IconLaUniversity": true,
"IconLaUserCircle": true,
Expand Down
3 changes: 2 additions & 1 deletion api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
"copy-prisma": "node copy.js",
"build": "run-s build-* copy-prisma",
"postinstall": "prisma generate --schema=../prisma/schema.prisma",
"start": "cross-env NODE_ENV=production node dist/app.js"
"start": "cross-env NODE_ENV=production node dist/app.js",
"studio": "cross-env DATABASE_URL=postgresql://postgres:@localhost:5632/mirai prisma studio --schema=../prisma/schema.prisma"
},
"prisma": {
"seed": "pnpm ts-node ../prisma/seed.ts"
Expand Down
10 changes: 9 additions & 1 deletion api/src/lib/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,15 @@ export function prismaQueryHelper(client: WithExcludeClient) {
account = await client.account.findFirst({
where: { email, id },
select: {
tenant: true,
tenant: {
include: {
basics: {
select: {
name: true,
},
},
},
},
...client.$exclude('account', ['password', 'otp', 'otpExpiry', 'emailToken']),
},
})
Expand Down
19 changes: 18 additions & 1 deletion api/src/lib/student.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export async function createStudent({
departmentId,
courseId,
// TODO: fix the code generation
code: [code ?? name, uniId].map(snakeCase).join('_'),
code: [code ?? name.toLowerCase(), uniId].map(snakeCase).join('_'),
uniId,
},
})
Expand All @@ -67,6 +67,23 @@ export async function createStudent({
},
})

const batch = await miraiClient.batch.findFirst({
where: { id: batchId },
select: { id: true, startsAt: true },
})

if (batch === null) return

await miraiClient.studentScore.create({
data: {
studentId,
courseStartedAt: batch.startsAt,
currentTerm: 0,
lateralEntry: false,
scores: '{}',
},
})

// create and link account
await miraiClient.account.create({
data: {
Expand Down
12 changes: 0 additions & 12 deletions api/src/routes/tickets.ts

This file was deleted.

36 changes: 36 additions & 0 deletions api/src/rpc/routers/student/basics.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { createRouter } from '../../createRouter'
import { z } from 'zod'
import { createStudentBasicsSchema } from '@mirai/app'
import { TRPCError } from '@trpc/server'

export const basicsRouter = createRouter()
.query('get', {
input: z.number(),
async resolve({ ctx, input }) {
const studentBasics = await ctx.prisma.studentBasics.findFirst({
where: { studentId: input },
})

if (studentBasics === null) {
throw new TRPCError({
code: 'NOT_FOUND',
message: 'Student basics not found !',
})
}

return studentBasics
},
})
.mutation('manage', {
input: createStudentBasicsSchema,
async resolve({ ctx, input }) {
const { studentId, ...data } = input
const result = await ctx.prisma.studentBasics.upsert({
where: { studentId },
create: input,
update: data,
})

return result
},
})
54 changes: 54 additions & 0 deletions api/src/rpc/routers/student/education.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { createStudentEducationSchema } from '@mirai/app'
import { TRPCError } from '@trpc/server'
import { z } from 'zod'
import { createRouter } from '../../createRouter'

export const educationRouter = createRouter()
.mutation('create', {
input: createStudentEducationSchema,
async resolve({ ctx, input }) {
const result = await ctx.prisma.studentEducation.createMany({
data: input,
})

return result
},
})
.mutation('update', {
input: createStudentEducationSchema.omit({ studentId: true }).partial().extend({ id: z.number() }),
async resolve({ ctx, input }) {
const { id, ...data } = input
const result = await ctx.prisma.studentEducation.update({
where: { id },
data,
})

return result
},
})
.mutation('remove', {
input: z.number(),
async resolve({ ctx, input }) {
try {
await ctx.prisma.studentEducation.delete({ where: { id: input } })
} catch (error) {
throw new TRPCError({ code: 'INTERNAL_SERVER_ERROR', message: 'Unable to delete experience' })
}
},
})
.query('get_all', {
input: z.number(),
async resolve({ ctx, input }) {
const educationDetails = await ctx.prisma.studentEducation.findMany({
where: { studentId: input },
})

if (educationDetails === null) {
throw new TRPCError({
code: 'NOT_FOUND',
message: 'Student education details not found !',
})
}
return educationDetails
},
})
39 changes: 36 additions & 3 deletions api/src/rpc/routers/student/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import { basicsRouter } from './basics'
import { TRPCError } from '@trpc/server'
import { z } from 'zod'
import { createRouter } from '../../createRouter'
import { certificationRouter } from './certifications'
import { experienceRouter } from './experience'
import { scoreRouter } from './score'
import { educationRouter } from './education'
import { projectRouter } from './project'

export const studentRouter = createRouter()
Expand All @@ -20,6 +23,7 @@ export const studentRouter = createRouter()

return nextCtx
})

.query('get', {
input: z.number(),
async resolve({ ctx, input }) {
Expand All @@ -36,12 +40,44 @@ export const studentRouter = createRouter()
},
projects: true,
score: true,
course: {
select: {
branchName: true,
programName: true,
programDuration: true,
scoreType: true,
},
},
Batch: {
select: {
name: true,
startsAt: true,
endsAt: true,
},
},
Department: {
select: {
name: true,
},
},
institute: {
select: {
name: true,
},
},
},
})

return studentData
},
})
.merge('basics.', basicsRouter)
.merge('score.', scoreRouter)
.merge('education.', educationRouter)
.merge('experience.', experienceRouter)
.merge('project.', projectRouter)
.merge('certification.', certificationRouter)

.mutation('skills.update', {
input: z.object({
studentId: z.number(),
Expand All @@ -57,6 +93,3 @@ export const studentRouter = createRouter()
return skillData
},
})
.merge('experience.', experienceRouter)
.merge('project.', projectRouter)
.merge('certification.', certificationRouter)
36 changes: 36 additions & 0 deletions api/src/rpc/routers/student/score.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { createRouter } from '../../createRouter'
import { z } from 'zod'
import { TRPCError } from '@trpc/server'
import { semUpdateSchema } from '@mirai/app'

export const scoreRouter = createRouter()
.query('get', {
input: z.number(),
async resolve({ ctx, input }) {
const scoreDetails = await ctx.prisma.studentScore.findFirst({
where: { studentId: input },
})

if (scoreDetails === null) {
throw new TRPCError({
code: 'NOT_FOUND',
message: 'Student score details not found !',
})
}

return scoreDetails
},
})
.mutation('update_score_card', {
input: z.object({ studentId: z.number(), data: z.record(semUpdateSchema) }),
async resolve({ ctx, input: { data, studentId } }) {
const scoreData = await ctx.prisma.studentScore.update({
where: { studentId },
data: {
scores: data,
},
})

return scoreData
},
})
19 changes: 16 additions & 3 deletions app/auto-imports.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,35 @@
declare global {
const IconLaBars: typeof import('~icons/la/bars.jsx')['default']
const IconLaBook: typeof import('~icons/la/book.jsx')['default']
const IconLaBookReader: typeof import('~icons/la/book-reader.jsx')['default']
const IconLaBuilding: typeof import('~icons/la/building.jsx')['default']
const IconLaCalendar: typeof import('~icons/la/calendar.jsx')['default']
const IconLaCheckCircleSolid: typeof import('~icons/la/check-circle-solid.jsx')['default']
const IconLaChevronDown: typeof import('~icons/la/chevron-down.jsx')['default']
const IconLaExclamationCircle: typeof import('~icons/la/exclamation-circle.jsx')['default']
const IconLaExclamationTriangle: typeof import('~icons/la/exclamation-triangle.jsx')['default']
const IconLaFileAltSolid: typeof import('~icons/la/file-alt-solid.jsx')['default']
const IconLaFlask: typeof import('~icons/la/flask.jsx')['default']
const IconLaGraduationCap: typeof import('~icons/la/graduation-cap.jsx')['default']
const IconLaHandsHelping: typeof import('~icons/la/hands-helping.jsx')['default']
const IconLaHome: typeof import('~icons/la/home.jsx')['default']
const IconLaHotel: typeof import('~icons/la/hotel.jsx')['default']
const IconLaIdCardSolid: typeof import('~icons/la/id-card-solid.jsx')['default']
const IconLaMailBulk: typeof import('~icons/la/mail-bulk.jsx')['default']
const IconLaMoneyBill: typeof import('~icons/la/money-bill.jsx')['default']
const IconLaMoon: typeof import('~icons/la/moon.jsx')['default']
const IconLaPassport: typeof import('~icons/la/passport.jsx')['default']
const IconLaPenSquare: typeof import('~icons/la/pen-square.jsx')['default']
const IconLaPlusCircle: typeof import('~icons/la/plus-circle.jsx')['default']
const IconLaRocket: typeof import('~icons/la/rocket.jsx')['default']
const IconLaRulerCombined: typeof import('~icons/la/ruler-combined.jsx')['default']
const IconLaSchool: typeof import('~icons/la/school.jsx')['default']
const IconLaShieldAlt: typeof import('~icons/la/shield-alt.jsx')['default']
const IconLaSitemap: typeof import('~icons/la/sitemap.jsx')['default']
const IconLaSortAmountDown: typeof import('~icons/la/sort-amount-down.jsx')['default']
const IconLaSortAmountUp: typeof import('~icons/la/sort-amount-up.jsx')['default']
const IconLaSun: typeof import('~icons/la/sun.jsx')['default']
const IconLaTicketAlt: typeof import('~icons/la/ticket-alt.jsx')['default']
const IconLaTimes: typeof import('~icons/la/times.jsx')['default']
const IconLaTimesCircle: typeof import('~icons/la/times-circle.jsx')['default']
const IconLaTrashAltSolid: typeof import('~icons/la/trash-alt-solid.jsx')['default']
const IconLaUndoAlt: typeof import('~icons/la/undo-alt.jsx')['default']
const IconLaUniversity: typeof import('~icons/la/university.jsx')['default']
const IconLaUserCircle: typeof import('~icons/la/user-circle.jsx')['default']
Expand Down
6 changes: 3 additions & 3 deletions app/src/components/globals/NavBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ export const NavBar: React.FC<Props> = () => {
<>
<div className="dropdown dropdown-end" onClick={() => setSidebar(false)}>
<button tabIndex={0} className="placeholder avatar">
<div className="h-8 w-8 rounded-full bg-primary text-base-content">
<span> {userData.name?.slice(0, 2).toUpperCase()} </span>
<div className="h-8 w-8 rounded-full bg-base-200 text-sm shadow">
<span> {(userData.name ?? userData?.tenant?.basics?.name)?.slice(0, 2).toUpperCase()} </span>
</div>
</button>
<ul
Expand All @@ -52,7 +52,7 @@ export const NavBar: React.FC<Props> = () => {
<li>
<div className="p-1 text-sm">
<span className="font-semibold text-base-content">
{userData.name} ({userData.role})
{userData.name ?? userData?.tenant?.basics?.name} ({userData.role})
</span>
</div>
</li>
Expand Down
2 changes: 1 addition & 1 deletion app/src/components/globals/SettingsModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export const SettingsModal: React.FC<Props> = ({ onClose }) => {
setTheme(theme === 'dark' ? 'corporate' : 'dark')
}}
>
<label className={clsx(['swap swap-rotate flex-none', theme === 'light' && 'swap-active'])}>
<label className={clsx(['swap-rotate swap flex-none', theme === 'light' && 'swap-active'])}>
<MIcon className="swap-on">
<IconLaSun />
</MIcon>
Expand Down
2 changes: 1 addition & 1 deletion app/src/components/globals/SideBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ export const SideBar: React.FC<Props> = ({ children }) => {
const breakpoint = useBreakpoint()

const tour = useRef<Tour | null>(null)
const [showDialog, setDialog] = useState(userData?.showTour ?? false)
const [showDialog, setDialog] = useState(userData?.role !== 'INSTITUTE' ? false : userData?.showTour ?? false)

async function onStart() {
setDialog(false)
Expand Down
Loading

0 comments on commit f70419e

Please sign in to comment.