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

[RN-92] 도서관 이용시간 알림 알림설정 기능 추가 #525

Merged
merged 1 commit into from
Jun 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
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ const PortalAuthenticationScreen = () => {
const [isNotAccountFlow] = useIsCurrentScreen([
'student_id_portal_authentication',
'mypage_account_portal_authentication',
'library_portal_authentication',
]);

const {changeAccountFlow, resetAccountFlow} = useAccountFlow();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ import {Icon, Txt} from '@uoslife/design-system';
import {useSuspenseQuery} from '@tanstack/react-query';
import AnimatePress from '../../../../components/animations/pressable_icon/AnimatePress';
import CardLayout from '../../../../components/molecules/common/cardLayout/CardLayout';
import UtilityService from '../../../../services/utility';
import Skeleton from '../../../../components/molecules/common/skeleton/Skeleton';
import LibraryServices from '../../services/library';

const LibraryUsageHistory = () => {
const {data, refetch} = useSuspenseQuery({
queryKey: ['getLibraryUsageStatus'],
queryFn: () => UtilityService.getLibraryUsageStatus(),
queryFn: () => LibraryServices.getLibraryUsageStatus(),
});

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ import {
LibraryRankingMajorName,
} from '../../../constants/libraryRanking/libraryRanking';
import useUserState from '../../../../../hooks/useUserState';
import UtilityService from '../../../../../services/utility';
import Select from '../../../../../components/molecules/common/select/Select';
import Skeleton from '../../../../../components/molecules/common/skeleton/Skeleton';
import LibraryServices from '../../../services/library';

const TRIANGLE_WIDTH = Dimensions.get('screen').width - 96;
const TRIANGLE_HEIGHT = TRIANGLE_WIDTH * (442 / 508);
Expand Down Expand Up @@ -96,15 +96,15 @@ const LibraryRanking = ({duration}: Props) => {
{
queryKey: ['getLibraryRanking', duration, major],
queryFn: () =>
UtilityService.getLibraryRanking({
LibraryServices.getLibraryRanking({
duration,
major,
}),
},
{
queryKey: ['getMyLibraryRanking', duration, major],
queryFn: () =>
UtilityService.getMyLibraryRanking({
LibraryServices.getMyLibraryRanking({
duration,
major,
}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ import GuidePopup from '../../../../../components/molecules/common/GuidePopup';
import boxShadowStyle from '../../../../../styles/boxShadow';
import useUserState from '../../../../../hooks/useUserState';
import customShowToast from '../../../../../configs/toast';
import UtilityService from '../../../../../services/utility';
import LibraryChallengeBoard from '../../molecules/LibraryChallengeBoard';
import LibraryServices from '../../../services/library';

export const ChallengUserStatusImgEnum: {
[key in ChallengeUserStatusType]: any;
Expand Down Expand Up @@ -45,7 +45,7 @@ const ChallengeScreen = () => {
const {data: challengeData, refetch} = useQuery({
queryKey: ['getChallengeData', 'MONTH', '시대생'],
queryFn: () =>
UtilityService.getMyLibraryRanking({
LibraryServices.getMyLibraryRanking({
duration: 'MONTH',
major: '시대생',
}),
Expand Down
208 changes: 208 additions & 0 deletions src/features/library/services/library.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
import {UtilAPI, CoreAPI} from '../../../api/services';
import {RecapInfoType} from '../../../api/services/core/libraryHistory/libraryHistoryAPI.type';
import {ErrorResponseType} from '../../../api/services/type';
import {
LibraryReservationType,
GetLibraryRankingRes,
GetMyLibraryRankingRes,
} from '../../../api/services/util/library/libraryAPI.type';
import storage from '../../../storage';
import {isAndroid} from '../../../utils/android/isAndroid';
import {LibraryStateNotificationBridge} from '../../../utils/android/libraryStateNotificationBridge';
import {LibraryDynamicIslandBridge} from '../../../utils/ios/libraryDynamicIslandBridge';
import {LibraryRankingMajorNameType} from '../constants/libraryRanking/libraryRanking';
import {LibraryRankingTabsType} from '../constants/libraryTabs';
import {
librarySeatStartTime,
libraryUsingStatus,
setLibrarySeatStartTime,
setLibraryUsingStatus,
} from '../storage/library';
import {
ReservationStatusType,
LibraryReservationAtomType,
DEFAULT_RESERVATION_STATUS,
} from '../store';
import {convertDateFormat} from '../utils/convertDateFormat';
import {endLibraryStateActivity} from '../utils/endLibraryStateActivity';

export default class LibraryServices {
static async getLibraryReservationInfo() {
try {
const response = await UtilAPI.getLibraryReservation({});
return response;
} catch (error) {
return undefined;
}
}

static getOutingStatus(
remainingSeconds: LibraryReservationType['remainingSeconds'],
): ReservationStatusType {
if (remainingSeconds < 30 * 60) return 'OUTING_DEFAULT';
return 'OUTING_NO_TIME';
}

static calculateDateInterval(seatStartTime: string) {
return (
new Date().valueOf() / 1000 -
new Date(convertDateFormat(seatStartTime)).valueOf() / 1000
);
}

static async getLibraryReservation(): Promise<LibraryReservationAtomType> {
// isLibraryStateActivity Parse 로직 분리시 동작 x
const isLibraryStateActivityNonParse = storage.getString(
'isLibraryStateActivity',
);
const isLibraryStateActivity = isLibraryStateActivityNonParse
? (JSON.parse(isLibraryStateActivityNonParse) as boolean)
: null;

try {
let isStudyRoom: boolean = false;
let status: ReservationStatusType = DEFAULT_RESERVATION_STATUS;

const response = await UtilAPI.getLibraryReservation({});

if (isLibraryStateActivity) this.startLibraryStateActivity(response);

if (response.status === 'STUDY_ROOM') isStudyRoom = true;

if (response.status !== 'OUTSIDE') status = 'USING';
else {
const outingStatus = this.getOutingStatus(response.remainingSeconds);
status = outingStatus;
}

return {
reservationStatus: status,
reservationInfo: response,
isStudyRoom,
};
} catch (error) {
const err = error as ErrorResponseType;

if (librarySeatStartTime) {
endLibraryStateActivity();
}

if (err.status === 500) {
return {
reservationStatus: 'NOT_PORTAL_VERIFICATION',
reservationInfo: null,
isStudyRoom: null,
};
}

return {
reservationStatus: 'NOT_USING',
reservationInfo: null,
isStudyRoom: null,
};
}
}

static startLibraryStateActivity(response: LibraryReservationType) {
if (librarySeatStartTime !== response.seatStartTime) {
if (isAndroid)
LibraryStateNotificationBridge.start({
seatRoomName: response.seatRoomName,
seatNumber: response.seatNo,
isUsing: response.status === 'SEAT',
dateInterval:
response.status === 'SEAT'
? this.calculateDateInterval(response.seatStartTime)
: response.remainingSeconds,
});
else
LibraryDynamicIslandBridge.onStartActivity({
seatRoomName: response.seatRoomName,
seatNumber: response.seatNo,
isUsing: response.status === 'SEAT',
dateInterval:
response.status === 'SEAT'
? this.calculateDateInterval(response.seatStartTime)
: response.remainingSeconds,
});
setLibrarySeatStartTime(response.seatStartTime);
setLibraryUsingStatus(response.status);
}

if (libraryUsingStatus !== response.status) {
if (isAndroid)
LibraryStateNotificationBridge.start({
seatRoomName: response.seatRoomName,
seatNumber: response.seatNo,
isUsing: response.status === 'SEAT',
dateInterval:
response.status === 'SEAT'
? this.calculateDateInterval(response.seatStartTime)
: response.remainingSeconds,
});
else
LibraryDynamicIslandBridge.onUpdateActivity({
isUsing: response.status === 'SEAT',
dateInterval:
response.status === 'SEAT'
? this.calculateDateInterval(response.seatStartTime)
: response.remainingSeconds,
});
setLibraryUsingStatus(response.status);
}
}

static async getLibraryUsageStatus(): Promise<RecapInfoType | null> {
try {
const res = await Promise.all([
CoreAPI.getLibraryHistories({year: 2024}),
CoreAPI.saveLibraryHistories({year: 2024}),
]);

return res[0];
} catch (error) {
return null;
}
}

static async getLibraryRanking({
duration,
major,
}: {
duration: LibraryRankingTabsType;
major: LibraryRankingMajorNameType;
}): Promise<GetLibraryRankingRes | null> {
try {
const res = await UtilAPI.getLibraryRanking({
duration,
major,
});
return res;
} catch (error) {
return null;
}
}

static async getMyLibraryRanking({
duration,
major,
}: {
duration: LibraryRankingTabsType;
major: LibraryRankingMajorNameType;
}): Promise<GetMyLibraryRankingRes | null> {
try {
const res = await UtilAPI.getMyLibraryRanking({
duration,
major,
});
try {
CoreAPI.saveLibraryHistories({year: 2024});
} catch (err) {
console.error(err);

Check warning on line 201 in src/features/library/services/library.ts

View workflow job for this annotation

GitHub Actions / release

Unexpected console statement
}
return res;
} catch (error) {
return null;
}
}
}
23 changes: 23 additions & 0 deletions src/features/library/storage/library.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import {ReservationStatusTypeFromServer} from '../../../api/services/util/library/libraryAPI.type';
import storage from '../../../storage';

export const librarySeatStartTime = storage.getString('librarySeatStartTime');
export const libraryUsingStatus = storage.getString('libraryUsingStatus') as
| ReservationStatusTypeFromServer
| undefined;

export const setLibrarySeatStartTime = (seatStartTime: string) => {
storage.set('librarySeatStartTime', seatStartTime);
};
export const setLibraryUsingStatus = (
usingStatus: ReservationStatusTypeFromServer,
) => {
storage.set('libraryUsingStatus', usingStatus);
};

export const deleteLibrarySeatStartTime = () => {
storage.delete('librarySeatStartTime');
};
export const deleteLibraryUsingStatus = () => {
storage.delete('libraryUsingStatus');
};
4 changes: 2 additions & 2 deletions src/features/library/store/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {atomWithSuspenseQuery} from 'jotai-tanstack-query';
import {atom} from 'jotai';
import {LibraryReservationType} from '../../../api/services/util/library/libraryAPI.type';
import UtilityService from '../../../services/utility';
import LibraryServices from '../services/library';

export type ReservationStatusType =
| 'USING'
Expand Down Expand Up @@ -35,7 +35,7 @@ const initialData: LibraryReservationAtomType = {
export const libraryReservationAtom =
atomWithSuspenseQuery<LibraryReservationAtomType>(get => ({
queryKey: ['getLibraryReservation'],
queryFn: () => UtilityService.getLibraryReservation(),
queryFn: () => LibraryServices.getLibraryReservation(),
initialData,
refetchInterval: get(isFocusedLibraryAtom)
? DEFAULT_GET_LIBRARY_RESERVATION_REFETCH_INTERVAL
Expand Down
10 changes: 10 additions & 0 deletions src/features/library/utils/convertDateFormat.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export const convertDateFormat = (format: string) => {
const year = format.substring(0, 4);
const month = format.substring(4, 6);
const day = format.substring(6, 8);
const hours = format.substring(8, 10);
const minutes = format.substring(10, 12);
const seconds = format.substring(12, 14);

return `${year}-${month}-${day}T${hours}:${minutes}:${seconds}`;
};
15 changes: 15 additions & 0 deletions src/features/library/utils/endLibraryStateActivity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import {isAndroid} from '../../../utils/android/isAndroid';
import {LibraryStateNotificationBridge} from '../../../utils/android/libraryStateNotificationBridge';
import {LibraryDynamicIslandBridge} from '../../../utils/ios/libraryDynamicIslandBridge';
import {
deleteLibrarySeatStartTime,
deleteLibraryUsingStatus,
} from '../storage/library';

export const endLibraryStateActivity = () => {
if (isAndroid) LibraryStateNotificationBridge.end();
else LibraryDynamicIslandBridge.onEndActivity();

deleteLibrarySeatStartTime();
deleteLibraryUsingStatus();
};
Loading
Loading