Skip to content

Commit

Permalink
WIP student frontend
Browse files Browse the repository at this point in the history
  • Loading branch information
nygrenh committed Sep 2, 2024
1 parent c3827c2 commit c81bcb0
Show file tree
Hide file tree
Showing 13 changed files with 199 additions and 145 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import AudioPlayer from "./moocfi/AudioPlayer/index"
import AuthorBlock from "./moocfi/AuthorBlock"
import AuthorInnerBlock from "./moocfi/AuthorInnerBlock"
import ChapterProgressBlock from "./moocfi/ChapterProgressBlock"
import CodeGiveawayBlock from "./moocfi/CodeGiveaway"
import CodeGiveawayBlock from "./moocfi/CodeGiveAway"
import ConditionalBlock from "./moocfi/ConditionalBlock"
import CongratulationsBlock from "./moocfi/CongratulationsBlock"
import CourseChapterGridBlock from "./moocfi/CourseChapterGridBlock"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { useTranslation } from "react-i18next"

import { claimCodeFromCodeGiveaway } from "@/services/backend"
import Button from "@/shared-module/common/components/Button"
import ErrorBanner from "@/shared-module/common/components/ErrorBanner"
import useToastMutation from "@/shared-module/common/hooks/useToastMutation"
import { assertNotNullOrUndefined } from "@/shared-module/common/utils/nullability"

interface ClaimCodeProps {
codeGiveawayId: string
onClaimed: () => void
}

const ClaimCode: React.FC<ClaimCodeProps> = ({ codeGiveawayId, onClaimed }) => {
const { t } = useTranslation()

const claimCodeMutation = useToastMutation(
() => claimCodeFromCodeGiveaway(assertNotNullOrUndefined(codeGiveawayId)),
{ notify: false },
)

return (
<>
{claimCodeMutation.isError && (
<ErrorBanner error={claimCodeMutation.error} variant="readOnly" />
)}
<Button
onClick={async () => {
await claimCodeMutation.mutateAsync()
onClaimed()
}}
variant="primary"
size="medium"
disabled={claimCodeMutation.isPending}
>
{t("claim-code")}
</Button>
</>
)
}

export default ClaimCode
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import styled from "@emotion/styled"
import { useQuery } from "@tanstack/react-query"
import { useTranslation } from "react-i18next"

import { BlockRendererProps } from "../.."
import InnerBlocks from "../../util/InnerBlocks"

import ClaimCode from "./ClaimCode"

import { getCodeGiveawayStatus } from "@/services/backend"
import ErrorBanner from "@/shared-module/common/components/ErrorBanner"
import { assertNotNullOrUndefined } from "@/shared-module/common/utils/nullability"

interface CodeGiveawayBlockProps {
code_giveaway_id: string | undefined | null
}

const Wrapper = styled.div`
border: 1px solid #ccc;
border-radius: 5px;
padding: 1rem;
`

const CodeGiveawayBlock: React.FC<
React.PropsWithChildren<BlockRendererProps<CodeGiveawayBlockProps>>
> = (props) => {
const { t } = useTranslation()

const codeGiveawayId = props.data.attributes.code_giveaway_id

const codeGiveawayStatusQuery = useQuery({
queryKey: ["fetchCodeGiveawayStatus", codeGiveawayId],
queryFn: () => getCodeGiveawayStatus(assertNotNullOrUndefined(codeGiveawayId)),
enabled: !!codeGiveawayId,
})

if (!codeGiveawayId) {
return <ErrorBanner variant="readOnly" error={t("error-no-code-giveaway-id")} />
}

if (codeGiveawayStatusQuery.isLoading) {
return null
}

if (codeGiveawayStatusQuery.isError) {
return <ErrorBanner error={codeGiveawayStatusQuery.error} variant="readOnly" />
}

if (
codeGiveawayStatusQuery.data?.tag === "Disabled" ||
codeGiveawayStatusQuery.data?.tag === "NotEligible" ||
!codeGiveawayStatusQuery.data
) {
return null
}

if (codeGiveawayStatusQuery.data?.tag === "Eligible") {
return (
<Wrapper>
<InnerBlocks parentBlockProps={props} />
<ClaimCode
codeGiveawayId={codeGiveawayId}
onClaimed={() => codeGiveawayStatusQuery.refetch()}
/>
</Wrapper>
)
}

return (
<Wrapper>
<InnerBlocks parentBlockProps={props} />
<p>{t("your-code-code", { code: codeGiveawayStatusQuery.data.given_code })}</p>
</Wrapper>
)
}

export default CodeGiveawayBlock

This file was deleted.

17 changes: 8 additions & 9 deletions services/course-material/src/services/backend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
ChaptersWithStatus,
ChatbotConversation,
ChatbotConversationInfo,
CodeGiveawayStatus,
Course,
CourseBackgroundQuestionsAndAnswers,
CourseInstance,
Expand Down Expand Up @@ -54,6 +55,7 @@ import {
isChaptersWithStatus,
isChatbotConversation,
isChatbotConversationInfo,
isCodeGiveawayStatus,
isCourse,
isCourseBackgroundQuestionsAndAnswers,
isCourseInstance,
Expand Down Expand Up @@ -88,7 +90,6 @@ import {
} from "@/shared-module/common/bindings.guard"
import {
isArray,
isBoolean,
isNull,
isNumber,
isObjectMap,
Expand Down Expand Up @@ -717,14 +718,12 @@ export const sendChatbotMessage = async (
return stream
}

export const fetchGivenCodeFromCodeGiveaway = async (id: string): Promise<string | null> => {
const response = await courseMaterialClient.get(`/code-giveaways/${id}/given-code`)
return validateResponse(response, isUnion(isString, isNull))
}

export const fetchCodesLeftInCodeGiveaway = async (id: string): Promise<boolean> => {
const response = await courseMaterialClient.get(`/code-giveaways/${id}/codes-left`)
return validateResponse(response, isBoolean)
/**
GET /api/v0/course-material/code-giveaways/:id/status - Returns information about a code giveaway.
*/
export const getCodeGiveawayStatus = async (id: string): Promise<CodeGiveawayStatus> => {
const response = await courseMaterialClient.get(`/code-giveaways/${id}/status`)
return validateResponse(response, isCodeGiveawayStatus)
}

export const claimCodeFromCodeGiveaway = async (id: string): Promise<string> => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ CREATE TABLE code_giveaways (
deleted_at TIMESTAMP WITH TIME ZONE,
course_id UUID NOT NULL REFERENCES courses(id),
course_module_id UUID REFERENCES course_modules(id),
enabled BOOLEAN NOT NULL DEFAULT FALSE,
enabled BOOLEAN NOT NULL DEFAULT TRUE,
name VARCHAR(2048) NOT NULL
);
CREATE TRIGGER set_timestamp BEFORE
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 12 additions & 5 deletions services/headless-lms/models/src/code_giveaway_codes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,12 +130,19 @@ pub async fn give_some_code_to_user(
let res = sqlx::query_as!(
CodeGiveawayCode,
r#"
UPDATE code_giveaway_codes
WITH to_update AS (
SELECT *
FROM code_giveaway_codes
WHERE code_giveaway_id = $1
AND code_given_to_user_id IS NULL
AND deleted_at IS NULL
LIMIT 1
)
UPDATE code_giveaway_codes cgc
SET code_given_to_user_id = $2
WHERE code_giveaway_id = $1
AND code_given_to_user_id IS NULL
AND deleted_at IS NULL
RETURNING *
FROM to_update
WHERE cgc.id = to_update.id
RETURNING cgc.*
"#,
code_giveaway_id,
user_id
Expand Down
29 changes: 14 additions & 15 deletions services/headless-lms/models/src/code_giveaways.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ pub struct NewCodeGiveaway {

#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
#[cfg_attr(feature = "ts_rs", derive(TS))]
#[serde(tag = "tag")]
pub enum CodeGiveawayStatus {
Disabled,
NotEligible,
Expand Down Expand Up @@ -114,21 +115,19 @@ pub async fn get_code_giveaway_status(
return Ok(CodeGiveawayStatus::Disabled);
}

if let Some(course_module_id) = code_giveaway.course_module_id {
let course_module_completions =
crate::course_module_completions::get_all_by_user_id_and_course_module_id(
conn,
user_id,
course_module_id,
)
.await?;

if !course_module_completions
.iter().any(|c| c.passed)
{
return Ok(CodeGiveawayStatus::NotEligible);
}
}
// if let Some(course_module_id) = code_giveaway.course_module_id {
// let course_module_completions =
// crate::course_module_completions::get_all_by_user_id_and_course_module_id(
// conn,
// user_id,
// course_module_id,
// )
// .await?;

// if !course_module_completions.iter().any(|c| c.passed) {
// return Ok(CodeGiveawayStatus::NotEligible);
// }
// }
let already_given_code =
crate::code_giveaway_codes::get_code_given_to_user(conn, code_giveaway_id, user_id).await?;

Expand Down
Loading

0 comments on commit c81bcb0

Please sign in to comment.