Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/my courses #74

Merged
merged 5 commits into from
Apr 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file.
130 changes: 130 additions & 0 deletions app/courses/my-courses/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
import Feather from '@expo/vector-icons/Feather';
import debounce from 'awesome-debounce-promise';
import { router, useRouter } from 'expo-router';
import { useCallback, useEffect, useState } from 'react';

import { CourseListView } from '@/api';
import BackButton from '@/components/BackButton';
import EmptyList from '@/components/EmptyList';
import Loading from '@/components/Loading';
import ScrollablePage from '@/components/ScrollablePage';
import Text from '@/components/Text';

Check warning on line 11 in app/courses/my-courses/index.tsx

View workflow job for this annotation

GitHub Actions / check-build

There should be no empty line within import group
import {} from '@/components/pages/courses/styles';

import { MyCourseSummary } from '@/components/pages/my-courses';
import {
CircleButton,
ContentBackground,
HeaderBackground,
HeaderWrapper,
MyCourseSummaryWrapper,
TopWrapper,
TransparentBackground,
Content,
TextContainer,
} from '@/components/pages/my-courses/styles';
import { useActionSheet } from '@/hooks/actionSheet';
import { useAuth } from '@/hooks/auth';
import { client } from '@/services/client';
import { showErrors } from '@/services/errors';
import theme from '@/styles/theme';

export default function MyCourses() {
const Router = useRouter();

Check warning on line 33 in app/courses/my-courses/index.tsx

View workflow job for this annotation

GitHub Actions / check-build

'Router' is assigned a value but never used
const auth = useAuth();
const [loadingCourses, setLoadingCourses] = useState(true);
const actionSheet = useActionSheet({
title: 'Atenção!',
message: 'Você precisa estar logado para gerenciar seus cursos.',
actions: ['Realizar Login', 'Criar conta'],
actionsCallbacks: [
() => router.navigate('/login'),
() => router.navigate('/sign-up'),
],
});

const getCourses = async () => {
try {
setLoadingCourses(true);
const courses =
await client.courses.listAllTeacherCoursesUsersMeCoursesGet();
setViewCourses(courses);
} catch (error) {
showErrors(error);
} finally {
setLoadingCourses(false);
}
};

const getCoursesDebounced = useCallback(debounce(getCourses, 500), []);

useEffect(() => {
getCoursesDebounced();
}, []);

const [viewCourses, setViewCourses] = useState<CourseListView[]>([]);

const onCoursePress = (myCourse: CourseListView) => {
if (!auth.user) {
actionSheet.show();
return;
}
router.navigate(`/courses/${myCourse.id}`);
};

return (
<ScrollablePage>
<TopWrapper>
<HeaderBackground
defaultSource={require('assets/gray.png')}
source={require('assets/courses.png')}
resizeMode="cover"
>
<TransparentBackground>
<ContentBackground>
<HeaderWrapper>
<BackButton />
<TextContainer>
<Text weight="regular" size="h1" color="light">
Meus Cursos
</Text>
</TextContainer>
<CircleButton
onPress={() => router.push('/courses/new-course')}
>
<Feather name="plus" size={24} color={theme.colors.light} />
</CircleButton>
</HeaderWrapper>
</ContentBackground>
</TransparentBackground>
</HeaderBackground>
</TopWrapper>

<Content>
{loadingCourses && <Loading />}

{!loadingCourses &&
viewCourses.map((course) => (
<MyCourseSummaryWrapper key={course.id}>
<MyCourseSummary
course={course}
onPress={() => onCoursePress(course)}
/>
</MyCourseSummaryWrapper>
))}

{!loadingCourses &&
viewCourses.map((course) => (
<MyCourseSummaryWrapper key={course.id}>
<MyCourseSummary
course={course}
onPress={() => onCoursePress(course)}
/>
</MyCourseSummaryWrapper>
))}

{!loadingCourses && viewCourses.length === 0 && <EmptyList />}
</Content>
</ScrollablePage>
);
}
2 changes: 1 addition & 1 deletion app/profile/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ export default function Profile() {
description: isTeacher
? 'Gerencie seu conteúdo'
: 'Cursos em andamento e disponíveis',
href: '/courses',
href: isTeacher ? '/courses/my-courses' : '/courses',
},
{
icon: 'video',
Expand Down
92 changes: 92 additions & 0 deletions components/pages/my-courses/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import Feather from '@expo/vector-icons/Feather';
import { router, useRouter } from 'expo-router';

Check warning on line 2 in components/pages/my-courses/index.tsx

View workflow job for this annotation

GitHub Actions / check-build

'useRouter' is defined but never used
import React from 'react';
import { useTheme } from 'styled-components/native';

import {
AuthorWrapper,
ContentContainer,
MyCourseViewBackground,
MyCourseViewWrapper,
StatusView,
StatusWrapper,
} from './styles';

import { CourseListView } from '@/api';
import Text from '@/components/Text';
import { useActionSheet } from '@/hooks/actionSheet';
import { moderateScale } from '@/utils/scale';

interface CourseSummaryProps {
course: CourseListView;
onPress: () => void;
}

export function MyCourseSummary({ course, onPress }: CourseSummaryProps) {
const theme = useTheme();
const actionSheet = useActionSheet({
title: 'Opções',
message: 'Escolha uma das opções a seguir',
actions: ['Editar', 'Excluir'],
actionsCallbacks: [
() => router.navigate('/courses'),
() => router.navigate('/courses'),
],
});
return (
<MyCourseViewWrapper onPress={onPress}>
<MyCourseViewBackground
defaultSource={require('assets/gray.png')}
source={{ uri: course.image_url || '' }}
resizeMode="cover"
imageStyle={{ borderRadius: moderateScale(25), width: '100%' }}
>
<ContentContainer>
<StatusWrapper>
{course.published_at && (
<StatusView color="light">
<Text size="h5" weight="bold" color="dark">
Publicado
</Text>
</StatusView>
)}

{!course.published_at && (
<StatusView color="">
<Text weight="light" color="light">
Não Publicado
</Text>
</StatusView>
)}
<Feather
onPress={actionSheet.show}
name="settings"
size={moderateScale(20)}
color={theme.colors.light}
style={{ marginRight: moderateScale(5) }}
/>
</StatusWrapper>

<Text size="h5" weight="bold" color="light">
{course.name}
</Text>

<AuthorWrapper>
<Feather
name="user"
size={moderateScale(15)}
color={theme.colors.light}
style={{ marginRight: moderateScale(5) }}
/>
<Text color="light">{course.author_name}</Text>
</AuthorWrapper>
<Text weight="light" color="light">
{course.chapters_count} Capítulos
</Text>

<Text color="light" style={{ marginTop: moderateScale(10) }} />
</ContentContainer>
</MyCourseViewBackground>
</MyCourseViewWrapper>
);
}
126 changes: 126 additions & 0 deletions components/pages/my-courses/styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import styled from 'styled-components/native';

import { moderateScale, verticalScale } from '@/utils/scale';

export const TopWrapper = styled.View`
height: ${verticalScale(100)}px;
width: 100%;
position: relative;
align-items: center;
z-index: 0;
`;

export const HeaderBackground = styled.ImageBackground`
width: 100%;
height: ${verticalScale(120)}px;
`;

export const HeaderWrapper = styled.View`
align-items: center;
flex-direction: row;
padding-top: ${verticalScale(20)}px;
`;

export const TransparentBackground = styled.SafeAreaView<TransparentProps>`
height: 100%;
width: 100%;
background-color: rgba(0, 0, 0, ${(props) => (props.darker ? '0.8' : '0.4')});
`;

export const DescriptionWrapper = styled.View`
flex-direction: row;
align-items: center;
margin-top: ${verticalScale(10)}px;
`;

export const ContentBackground = styled.View`
height: 100%;
width: 100%;
padding: ${moderateScale(20)}px;
`;

export const MyCourseViewWrapper = styled.TouchableOpacity`
width: 100%;
align-items: center;
justify-content: center;
`;

export const MyCourseViewBackground = styled.ImageBackground`
width: 95%;
height: ${verticalScale(200)}px;
border-radius: ${moderateScale(25)}px;
align-items: column;
`;

export const MyCourseSummaryWrapper = styled.View`
margin: ${verticalScale(10)}px 0;
`;

interface TransparentProps {
darker?: boolean;
}

export const Content = styled.View`
margin-top: ${verticalScale(30)}px;

flex: 1;
padding-bottom: ${verticalScale(20)}px;
`;

export const TitleContainer = styled.View`
padding: ${moderateScale(10)}px;
`;

export const CircleButton = styled.TouchableOpacity`
align-items: center;
justify-content: center;
width: ${moderateScale(40)}px;
height: ${moderateScale(40)}px;
border-radius: ${moderateScale(40)}px;
background-color: ${(props) => props.theme.colors.primary};
`;

export const TextContainer = styled.View`
flex: 1;
`;

interface StatusViewProps {
color: string;
}
export const AuthorWrapper = styled.View`
flex-direction: row;
align-items: center;
margin-top: ${verticalScale(5)}px;
margin-bottom: ${verticalScale(15)}px;
`;

export const StatusView = styled.View<StatusViewProps>`
background-color: ${(props) =>
props.color === 'light'
? props.theme.colors.light
: props.theme.colors.statusRed};
height: ${moderateScale(30)}px;
width: ${moderateScale(120)}px;
justify-content: center;
align-items: center;
border-radius: ${moderateScale(25)}px;
`;

export const StatusWrapper = styled.View`
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
margin-bottom: ${moderateScale(15)}px;
width: 100%;
`;

export const ContentContainer = styled.View`
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.4);
align-items: flex-start;
justify-content: center;
border-radius: ${moderateScale(25)}px;
padding: ${moderateScale(20)}px;
`;
1 change: 1 addition & 0 deletions styles/theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export default {
textBody: '#373737',
dark: '#000000',
light: '#FFFFFF',
statusRed: '#F27575',
success: '#398200',
},
};
Loading