Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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
2 changes: 2 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@
EXPO_PUBLIC_POSTHOG_API_KEY=
# Optional edition name
EXPO_PUBLIC_EDITION_NAME=
# Conference date in YYYY-MM-DD format
EXPO_PUBLIC_CONFERENCE_DATE=
27 changes: 19 additions & 8 deletions app/(tabs)/home/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,22 @@
import { ScrollContent } from '../../../components/base/scroll-content';
import { ErrorMessage } from '../../../components/common/error-message';
import { Header } from '../../../components/common/header';
import { HomePrText } from '../../../components/common/home-pr-text';
import { SectionTitle } from '../../../components/common/sectiontitle';
import { Separator } from '../../../components/common/separator';
import { StatusMessage } from '../../../components/common/status-message';
import { HomeNewsList } from '../../../components/news/layouts/home-news-list';
import { NewsItemSkeletonList } from '../../../components/news/layouts/news-item-skeleton-list';
import { HomePresentationList } from '../../../components/schedule/layouts/home-presentation-list';
import { PresentationItemSkeletonList } from '../../../components/schedule/layouts/presentation-item-skeleton-list';
import { useConference } from '../../../hooks/use-conference';
import { useNews } from '../../../hooks/use-news';
import { isConferenceDay } from '../../../utils/date.utils';

export default function HomePage() {
const conference = useConference();
const news = useNews();

Check failure on line 22 in app/(tabs)/home/index.tsx

View workflow job for this annotation

GitHub Actions / ESLint Check

'news' is assigned a value but never used
const { t } = useTranslation();
const isArchive = useFeatureFlag('archive_mode');
const showPresentations = isConferenceDay();

return (
<Screen analyticsScreenName='home'>
Expand All @@ -36,16 +38,25 @@
</>
)}

<SectionTitle>{t('home.presentationTitle')}</SectionTitle>
{conference.isLoading && <PresentationItemSkeletonList className='mx-0' />}
{conference.isError && <ErrorMessage>{t('home.error')}</ErrorMessage>}
{!conference.isError && !conference.isLoading && (
<HomePresentationList presentations={conference.data?.presentations ?? []} />
{showPresentations && (
<>
<SectionTitle>{t('home.presentationTitle')}</SectionTitle>
{conference.isLoading && <PresentationItemSkeletonList className='mx-0' />}
{conference.isError && <ErrorMessage>{t('home.error')}</ErrorMessage>}
{!conference.isError && !conference.isLoading && (
<HomePresentationList presentations={conference.data?.presentations ?? []} />
)}
<Separator className='mb-5' />
</>
)}
<Separator className='mb-5' />

Check failure on line 52 in app/(tabs)/home/index.tsx

View workflow job for this annotation

GitHub Actions / ESLint Check

Delete `········`
{!showPresentations && <HomePrText />}

{/*
<SectionTitle>{t('home.newsTitle')}</SectionTitle>
{news.isLoading && <NewsItemSkeletonList />}
{news.data && <HomeNewsList news={news.data.news} />}
*/}
</ScrollContent>
</Screen>
);
Expand Down
1 change: 1 addition & 0 deletions assets/Full.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions assets/FullSand.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/adaptive-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/icon-dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/icon-light.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/icon-tinted.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/notification-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/splash-icon-dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/splash-icon-light.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
46 changes: 14 additions & 32 deletions components/base/logo.tsx
Original file line number Diff line number Diff line change
@@ -1,42 +1,24 @@
import { Image } from 'expo-image';
import { useColorScheme } from 'react-native';
import Svg, { Path } from 'react-native-svg';

const logoWidth = 838;
const logoHeight = 134;
const logoWidth = 782.78;
const logoHeight = 310.59;

const logoResize = 2 / 7;
const logoResize = 70 / logoHeight;

export function Logo() {
const colorScheme = useColorScheme();
const fillColor = colorScheme === 'dark' ? 'white' : 'black';
const logoSource =

Check failure on line 11 in components/base/logo.tsx

View workflow job for this annotation

GitHub Actions / ESLint Check

Delete `⏎···`
colorScheme === 'dark' ? require('../../assets/FullSand.svg') : require('../../assets/Full.svg');

return (
<Svg width={logoWidth * logoResize} height={logoHeight * logoResize} viewBox='0 0 838 134'>
<Path
d='M239.904 133.665V0.426167C262.717 1.43276 286.663 -0.915961 309.345 0.426167C357.709 3.30683 375.2 48.4727 363.325 91.1671C347.88 146.694 283.394 131.423 239.904 133.657V133.665ZM280.436 99.6863H299.377C334.301 99.6863 335.768 34.3967 296.72 34.3967H280.436V99.6863Z'
fill='#EB0028'
/>
<Path
d='M232.594 0.426147V34.4049H162.151V51.0587H232.594V83.0325H162.151V99.6863H232.594V133.665H121.611V0.426147H232.594Z'
fill='#EB0028'
/>
<Path d='M114.968 0.426147V34.4049H77.7541V133.665H37.2144V34.4049H0V0.426147H114.968Z' fill='#EB0028' />
<Path
d='M625.007 4.4198L670.861 119.679L715.72 4.4198H732.999V133.665H721.034L721.694 19.085C720.741 18.9295 720.822 20.2062 720.545 20.91C716.78 30.4522 713.821 40.69 710.064 50.3795C699.273 78.2205 687.145 105.734 675.857 133.338L664.878 133.002L619.693 19.0686L620.027 133.665H608.062V5.4264L609.057 4.42798H625.007V4.4198Z'
fill={fillColor}
/>
<Path
d='M498.409 5.42638C498.995 4.47707 499.737 4.50981 500.699 4.39524C511.816 3.08584 545.526 3.60142 555.974 6.34296C575.918 11.5805 585.756 33.161 577.499 52.0735C573.823 60.4782 568.159 62.9006 560.481 66.3213C559.683 66.6732 559.283 66.0104 559.544 67.7126C568.322 68.0072 576.994 74.8815 581.102 82.4105C593.319 104.785 578.054 133.665 551.899 133.665H498.4V5.42638H498.409ZM511.042 63.0479H546.593C550.783 63.0479 558.533 59.0542 561.565 56.0753C575.185 42.7032 567.018 15.7542 547.262 15.7542H511.042V63.056V63.0479ZM511.042 122.339H552.576C553.969 122.339 560.025 120.154 561.574 119.368C578.836 110.62 576.065 85.5121 560.009 76.9192C558.688 76.2154 552.29 73.7112 551.247 73.7112H511.042V122.347V122.339Z'
fill={fillColor}
/>
<Path
d='M401.054 0.426147L412.024 20.4108L424.307 0.426147H453.216L426.638 40.7309L454.544 82.3696H424.975L413.01 62.3768C412.081 62.1722 411.894 62.9251 411.47 63.498C407.476 68.7846 404.232 76.6083 400.728 82.3696H370.824L398.723 40.7309L371.484 0.426147H401.054Z'
fill='#EB0028'
/>
<Path
d='M837.331 15.746H774.199V63.0479H832.343L833.232 64.1527C833.052 67.3443 834.332 71.8372 832.343 74.3741H774.199V122.339H838V133.665H762.242V4.4198H836.337L837.331 5.41821V15.746Z'
fill={fillColor}
/>
</Svg>
<Image
source={logoSource}
style={{
width: logoWidth * logoResize,
height: logoHeight * logoResize,
}}
contentFit='contain'
/>
);
}
29 changes: 29 additions & 0 deletions components/common/home-pr-text.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
import { Linking, Text, View } from 'react-native';

import { StyledButton } from './styled-button';

export function HomePrText() {
const { t } = useTranslation();

return (
<View className='flex-1 items-center justify-center p-6 mt-10 gap-6'>
<Text className='text-center text-lg font-medium opacity-80 text-black dark:text-white'>

Check failure on line 12 in components/common/home-pr-text.tsx

View workflow job for this annotation

GitHub Actions / ESLint Check

Replace `⏎········{t('home.prText')}⏎······` with `{t('home.prText')}`
{t('home.prText')}
</Text>
<View className='gap-2 items-center justify-center w-full'>
<Text className='text-center text-base opacity-70 text-black dark:text-white'>
{t('home.prRegistrationPre')}
</Text>
<StyledButton
variant='primary'
className='w-full'
onPress={() => Linking.openURL(t('home.prRegistrationLink'))}
>
{t('home.prRegistrationBtn')}
</StyledButton>
</View>
</View>
);
}
20 changes: 13 additions & 7 deletions components/schedule/elements/presentation-item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { useFavoritePresentations } from '../../../contexts/favorite-presentatio
import { ConferenceService } from '../../../services/conference.service';
import { PresentationDto } from '../../../types/conference-api.type';
import { cn } from '../../../utils/common.utils';
import { isConferenceDay } from '../../../utils/date.utils';
import { isPresentationPast } from '../../../utils/presentation.utils';
import { ItemCard } from '../../base/item-card';
import { StyledText } from '../../base/text';
Expand All @@ -21,7 +22,8 @@ export function PresentationItem({ presentation, className, ...props }: Presenta
const { isFavoritePresentation } = useFavoritePresentations();
const isArchive = useFeatureFlag('archive_mode');
const router = useNavigation<NativeStackNavigationProp<{ 'presentation-details': { id: string } }>>();
const isPast = isPresentationPast(presentation) && !isArchive;
const isConference = isConferenceDay();
const isPast = isPresentationPast(presentation) && !isArchive && isConference;
const isFavorite = isFavoritePresentation(presentation.slug);
const startTime = ConferenceService.getFormattedTimestamp(presentation.startTime);
const endTime = ConferenceService.getFormattedTimestamp(presentation.endTime);
Expand All @@ -40,18 +42,22 @@ export function PresentationItem({ presentation, className, ...props }: Presenta
onPress={onPress}
{...props}
>
<Image source={{ uri: presentation.presenter.pictureUrl }} className='rounded-full h-14 w-14' />
{presentation.presenter && (
<Image source={{ uri: presentation.presenter.pictureUrl }} className='rounded-full h-14 w-14' />
)}
<View className='flex-col gap-2 flex-1 mx-2'>
<StyledText className='text-xl' numberOfLines={1}>
{presentation.title}
</StyledText>
<View className='flex-row overflow-hidden'>
<StyledText className='text-background-400 dark:text-background-400 flex-shrink' numberOfLines={1}>
{presentation.presenter.name}
</StyledText>
{presentation.presenter && (
<StyledText className='text-background-400 dark:text-background-400 flex-shrink' numberOfLines={1}>
{presentation.presenter.name}
</StyledText>
)}
<StyledText className='text-background-400 dark:text-background-400' numberOfLines={1}>
{' '}
{startTime} - {endTime}
{presentation.presenter && ' • '}
{startTime} - {endTime}
</StyledText>
</View>
</View>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,17 @@ import { View } from 'react-native';

import { PresentationDto } from '../../../types/conference-api.type';
import { cn } from '../../../utils/common.utils';
import { isConferenceDay } from '../../../utils/date.utils';
import { isPresentationCurrent, isPresentationUpcoming } from '../../../utils/presentation.utils';

interface PresentationStatusIndicatorProps {
presentation: PresentationDto;
}

export function PresentationStatusIndicator({ presentation }: PresentationStatusIndicatorProps) {
const isCurrent = isPresentationCurrent(presentation);
const isUpcoming = isPresentationUpcoming(presentation);
const isConference = isConferenceDay();
const isCurrent = isConference && isPresentationCurrent(presentation);
const isUpcoming = isConference && isPresentationUpcoming(presentation);
return (
<View
className={cn('p-1 rounded-full', {
Expand Down
2 changes: 1 addition & 1 deletion components/schedule/layouts/presentation-details-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export function PresentationDetailsPage({ slug }: ScheduleDetailsPageProps) {
<Subtitle>
{data.room} • {startTime} - {endTime}
</Subtitle>
<Subtitle>{data.presenter.name}</Subtitle>
{data.presenter && <Subtitle>{data.presenter.name}</Subtitle>}
</>
)}
</Header>
Expand Down
29 changes: 27 additions & 2 deletions config/axios.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,37 @@
import { posthog } from './posthog.config';

const featureFlagName = 'api_base_url';
const DEFAULT_API_URL = 'https://konf-api.kir-dev.hu';

console.log(`[Axios] Initializing with baseURL: ${DEFAULT_API_URL}`);

export const axiosInstance = axios.create({
baseURL: '',
baseURL: DEFAULT_API_URL,
});

posthog.onFeatureFlag(featureFlagName, () => {
const baseUrl = posthog.getFeatureFlagPayload(featureFlagName);
axiosInstance.defaults.baseURL = baseUrl?.toString() ?? '';
if (baseUrl) {
const newBaseUrl = baseUrl.toString();
console.log(`[Axios] PostHog updated baseURL to: ${newBaseUrl}`);
axiosInstance.defaults.baseURL = newBaseUrl;
} else {
console.log(`[Axios] PostHog feature flag payload empty, keeping: ${axiosInstance.defaults.baseURL}`);
}
});

axiosInstance.interceptors.request.use((config) => {

Check failure on line 25 in config/axios.config.ts

View workflow job for this annotation

GitHub Actions / ESLint Check

Insert `⏎··`
console.log(`[Axios Request] ${config.method?.toUpperCase()} ${config.baseURL}${config.url}`, config.data ?? '');

Check failure on line 26 in config/axios.config.ts

View workflow job for this annotation

GitHub Actions / ESLint Check

Insert `··`
return config;

Check failure on line 27 in config/axios.config.ts

View workflow job for this annotation

GitHub Actions / ESLint Check

Insert `··`
Comment thread
peterlipt marked this conversation as resolved.
Outdated
}, (error) => {

Check failure on line 28 in config/axios.config.ts

View workflow job for this annotation

GitHub Actions / ESLint Check

Replace `},` with `··},⏎·`
console.error(`[Axios Request Error]`, error);

Check failure on line 29 in config/axios.config.ts

View workflow job for this annotation

GitHub Actions / ESLint Check

Insert `··`
return Promise.reject(error);

Check failure on line 30 in config/axios.config.ts

View workflow job for this annotation

GitHub Actions / ESLint Check

Replace `··` with `····`
});

axiosInstance.interceptors.response.use((response) => {
console.log(`[Axios Response] ${response.status} ${response.config.url}`, response.data);
return response;
}, (error) => {
console.error(`[Axios Response Error] ${error.response?.status} ${error.config?.url}`, error.response?.data ?? error.message);
return Promise.reject(error);
Comment thread
peterlipt marked this conversation as resolved.
Outdated
});
30 changes: 15 additions & 15 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,32 +30,32 @@
"date-fns": "^4.1.0",
"dotenv": "^16.5.0",
"env-var": "^7.5.0",
"expo": "^53.0.7",
"expo-application": "~6.1.4",
"expo-asset": "~11.1.5",
"expo-constants": "~17.1.5",
"expo": "~53.0.26",
"expo-application": "~6.1.5",
"expo-asset": "~11.1.7",
"expo-constants": "~17.1.8",
"expo-device": "~7.1.4",
"expo-file-system": "~18.1.9",
"expo-image": "^2.1.6",
"expo-linking": "^7.1.4",
"expo-localization": "^16.1.5",
"expo-notifications": "~0.31.1",
"expo-router": "~5.0.5",
"expo-splash-screen": "~0.30.8",
"expo-file-system": "~18.1.11",
"expo-image": "~2.4.1",
"expo-linking": "~7.1.7",
"expo-localization": "~16.1.6",
"expo-notifications": "~0.31.5",
"expo-router": "~5.1.11",
"expo-splash-screen": "~0.30.10",
"expo-status-bar": "~2.2.3",
"expo-updates": "~0.28.12",
"expo-updates": "~0.28.18",
"i18next": "~25.0.2",
"jest": "~29.7.0",
"jest-expo": "~53.0.4",
"jest-expo": "~53.0.14",
"nativewind": "~4.1.23",
"posthog-react-native": "~3.15.1",
"react": "19.0.0",
"react-i18next": "~15.5.1",
"react-native": "0.79.2",
"react-native": "0.79.6",
"react-native-gesture-handler": "~2.24.0",
"react-native-reanimated": "~3.17.5",
"react-native-safe-area-context": "~5.4.0",
"react-native-screens": "~4.10.0",
"react-native-screens": "~4.11.1",
"react-native-svg": "~15.11.2",
"tailwind-merge": "~3.2.0"
},
Expand Down
14 changes: 10 additions & 4 deletions services/conference.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { format, isAfter, isBefore } from 'date-fns';

import { axiosInstance } from '../config/axios.config';
import { FullConferenceDto } from '../types/conference-api.type';
import { parseTime } from '../utils/presentation.utils';

export class ConferenceService {
static async getConferenceData(): Promise<FullConferenceDto> {
Expand All @@ -13,8 +14,8 @@ export class ConferenceService {

private static sortPresentationsByStartDate(conference: FullConferenceDto) {
return conference.presentations.sort((a, b) => {
const aStartDate = new Date(a.startTime);
const bStartDate = new Date(b.startTime);
const aStartDate = parseTime(a.startTime);
const bStartDate = parseTime(b.startTime);
if (isBefore(aStartDate, bStartDate)) {
return -1;
}
Expand All @@ -26,16 +27,21 @@ export class ConferenceService {
}

static getFormattedTimestamp(timestamp: string) {
if (/^\d{2}:\d{2}$/.test(timestamp)) {
return timestamp;
}
try {
return format(new Date(timestamp), 'HH:mm');
} catch {
return 'n/a';
return timestamp || 'n/a';
}
}

static prefixConferenceImages(conference: FullConferenceDto) {
conference.presentations.forEach((p) => {
p.presenter.pictureUrl = ConferenceService.prefixPresenterImage(p.presenter);
if (p.presenter) {
p.presenter.pictureUrl = ConferenceService.prefixPresenterImage(p.presenter);
}
});
return conference;
}
Expand Down
8 changes: 8 additions & 0 deletions services/i18n_data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ export const resources = {
empty: 'The current program will appear here.',
noNews: 'No news available, check back later!',
archive: 'This is an archived version of the Simonyi Conference. Some features may be disabled.',
prText: 'The Simonyi Conference will be held on March 24, 2026! We look forward to seeing you there!',
prRegistrationPre: 'Want to join us? Register now!',
prRegistrationLink: 'https://konferencia.simonyi.bme.hu',
prRegistrationBtn: 'Go to registration',
},
presentations: {
title: 'Schedule',
Expand Down Expand Up @@ -77,6 +81,10 @@ export const resources = {
empty: 'Az aktuális programok itt fognak megjelenni.',
noNews: 'Nincsenek hírek, nézz vissza később!',
archive: 'Ez egy archivált verzió a Simonyi Konferenciáról. Néhány funkció letiltva lehet.',
prText: 'A Simonyi Konferencia 2026. március 24-én kerül megrendezésre! Várunk sok szeretettel!',
prRegistrationPre: 'Szeretnél részt venni az eseményen? Regisztrálj még ma!',
prRegistrationLink: 'https://konferencia.simonyi.bme.hu',
prRegistrationBtn: 'Tovább a regisztrációra',
},
presentations: {
title: 'Programterv',
Expand Down
Loading
Loading