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

Implémentation de TurboSelf #277

Open
wants to merge 23 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
96f203f
feat(canteen): enabling external services tabs, and canteen tab
raphckrman Oct 4, 2024
015c1a7
fix(canteen): incorrect remaining meals and add toFixed for balance
raphckrman Oct 4, 2024
fa2f2e5
feat(canteen): improvement on history, upgrading to turboself-api
raphckrman Oct 4, 2024
9d9ac75
fix(canteen): history spam, support multi balances
raphckrman Oct 4, 2024
4627247
feat(canteen): support multi histories
raphckrman Oct 4, 2024
021bd6c
feat(canteen): add pronote menu
raphckrman Oct 4, 2024
406ef19
fix(canteen): fix reload account
raphckrman Oct 5, 2024
7c95fe3
feature(widgets): add QRCode canteen widget
raphckrman Oct 5, 2024
ae42cc0
feature(widgets): add a widget for restaurant balances
raphckrman Oct 6, 2024
45c18f2
fix(widgets): correct singular/plural text for remaining meals
raphckrman Oct 6, 2024
a4cfd47
feature(canteen): add qcodes support
raphckrman Oct 6, 2024
893151d
feature(canteen): add history
raphckrman Oct 6, 2024
d6e6108
feat(canteen): add booking
raphckrman Oct 7, 2024
bdf839c
fix(menu): correct singular/plural text for available bookings
raphckrman Oct 7, 2024
9456f9e
feat(account): enhance booking functionality and improve error handling
raphckrman Oct 7, 2024
915e12b
fix(widget): correct singular/plural text
raphckrman Oct 7, 2024
7eff86f
fix(canteen): remove useless import and fix types for History
raphckrman Oct 7, 2024
5507b03
fix(canteen): crash when the user doesn't have any external account l…
raphckrman Oct 7, 2024
727f8c4
fix(widgets): duplicated text in RestaurantQRCode
raphckrman Oct 8, 2024
c0d7d7f
fix(canteen): fix reload accounts, update babel config, and fix booki…
raphckrman Oct 13, 2024
f3c4a00
fix(canteen): booking switch state was incorrect
raphckrman Oct 16, 2024
6a35573
fix(canteen): attempt to fix crash on QRCode page
raphckrman Oct 16, 2024
f1c6e2f
remove useless imports in History.tsx
raphckrman Oct 17, 2024
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
220 changes: 113 additions & 107 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@
"reanimated-color-picker": "^3.0.4",
"scolengo-api": "^3.0.5",
"text-encoding": "^0.7.0",
"turbawself": "^1.1.1",
"turboself-api": "^2.0.2",
"zustand": "^4.5.2"
},
"devDependencies": {
Expand Down
4 changes: 2 additions & 2 deletions src/components/Restaurant/RestaurantCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ const RestaurantCard: React.FC<RestaurantCardProps> = ({ solde, repas }) => {
fontSize: 30,
}}
>
{solde} €
{solde.toFixed(2)} €
</Text>
</View>

Expand All @@ -71,7 +71,7 @@ const RestaurantCard: React.FC<RestaurantCardProps> = ({ solde, repas }) => {
fontSize: 30,
}}
>
{repas}
{repas}
</Text>
</View>
</View>
Expand Down
9 changes: 7 additions & 2 deletions src/router/helpers/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { AddonPlacementManifest } from "@/addons/types";
import type { Chat } from "@/services/shared/Chat";
import type { Grade } from "@/services/shared/Grade";
import { Homework } from "@/services/shared/Homework";
import { ReservationHistory } from "@/services/shared/ReservationHistory";
import type { AccountService } from "@/stores/account/types";
import { Log } from "@/utils/logger/logger";
import type { CurrentPosition } from "@/utils/native/location";
Expand Down Expand Up @@ -112,8 +113,12 @@ export type RouteParameters = {
SettingsDonorsList: undefined;

Menu?: undefined;
RestaurantQrCode: undefined;
RestaurantHistory: undefined;
RestaurantQrCode: {
QrCodes: number[]
};
RestaurantHistory: {
histories: ReservationHistory[]
};

Messages: undefined;
ChatCreate: undefined;
Expand Down
2 changes: 1 addition & 1 deletion src/router/screens/account/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export const screens = [
tabBarLabel: "Messages",
tabBarLottie: require("@/../assets/lottie/tab_chat.json"),
}),
createScreen("Menu", PlaceholderScreen, {
createScreen("Menu", Menu, {
headerTitle: "Cantine",
tabBarLabel: "Cantine",
tabBarLottie: require("@/../assets/lottie/tab_pizza.json"),
Expand Down
5 changes: 4 additions & 1 deletion src/services/balance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@ export const balanceFromExternal = async (account: ExternalAccount): Promise<Bal
case AccountService.Turboself: {
const { getBalance } = await import("./turboself/balance");
const balance = await getBalance(account);
return [balance];
return balance;
}
case AccountService.ARD: {
const { balance } = await import("./ard/balance");
return balance(account);
}
default: {
return [];
}
}
};
34 changes: 34 additions & 0 deletions src/services/booking.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { AccountService, type ExternalAccount } from "@/stores/account/types";
import type { BookingDay, BookingTerminal } from "./shared/Booking";

export const getBookingsAvailableFromExternal = async (account: ExternalAccount, weekNumber?: number): Promise<BookingTerminal[]> => {
switch (account.service) {
case AccountService.Turboself: {
const { getBookingWeek } = await import("./turboself/booking");
const bookings = await getBookingWeek(account, weekNumber);
console.log(weekNumber);
console.log(bookings[0].days[0].booked);
return bookings;
}
case AccountService.ARD: {
// TODO: Implement ARD
return [];
}
default: {
return [];
}
}
};

export const bookDayFromExternal = async (account: ExternalAccount, id: string, date: Date, booked: boolean): Promise<BookingDay | null> => {
switch (account.service) {
case AccountService.Turboself: {
const { bookDay } = await import("./turboself/booking");
const bookedDay = await bookDay(account, id, date, booked);
return bookedDay;
}
case AccountService.ARD: {
return null;
}
}
};
15 changes: 15 additions & 0 deletions src/services/menu.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { type Account, AccountService } from "@/stores/account/types";
import { Menu } from "pawnote";

export async function getMenu <T extends Account> (account: Account, date: Date): Promise<Menu> {
switch (account.service) {
case AccountService.Pronote: {
const { getMenu } = await import("./pronote/menu");
const menu = await getMenu(account, date);
return menu;
}
default: {
throw new Error("Service not implemented.");
}
}
}
21 changes: 21 additions & 0 deletions src/services/pronote/menu.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { PronoteAccount } from "@/stores/account/types";
import { ErrorServiceUnauthenticated } from "../shared/errors";
import pronote, { Menu } from "pawnote";

export const getMenu = async (account: PronoteAccount, date: Date): Promise<Menu> => {
if (!account.instance) {
throw new ErrorServiceUnauthenticated("pronote");
}

const menu = await pronote.menus(account.instance, date);
if (!menu.days || menu.days.length === 0) {
return { date };
}
const day = menu.days[0];

if (day.date?.getTime() !== date.getTime()) {
return { date };
}

return day;
};
19 changes: 19 additions & 0 deletions src/services/qrcode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { AccountService, type ExternalAccount } from "@/stores/account/types";
import type { Balance } from "./shared/Balance";

export const qrcodeFromExternal = async (account: ExternalAccount): Promise<number> => {
switch (account.service) {
case AccountService.Turboself: {
const { getQRCode } = await import("./turboself/qrcode");
const QRCode = await getQRCode(account);
return QRCode;
}
case AccountService.ARD: {
// TODO: Implement ARD
return 0;
}
default: {
return 0;
}
}
};
2 changes: 1 addition & 1 deletion src/services/reload-account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export async function reload <T extends Account> (account: T): Promise<Reconnect
const { reload } = await import("./turboself/reload");
const auth = await reload(account);
// keep instance the same
return { instance: undefined, authentication: { auth, session: account.authentication.session } };
return { instance: undefined, authentication: { session: auth } };
}
case AccountService.ARD: {
const { reload } = await import("./ard/reload");
Expand Down
3 changes: 3 additions & 0 deletions src/services/reservation-history.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,8 @@ export const reservationHistoryFromExternal = async (account: ExternalAccount):
const { history: getHistory } = await import("./ard/history");
return getHistory(account);
}
default: {
return [];
}
}
};
19 changes: 19 additions & 0 deletions src/services/shared/Booking.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { ARDAccount, TurboselfAccount } from "@/stores/account/types";

export interface BookingTerminal {
id: string;
week: number;
from: Date;
to: Date;
terminalLabel: string;
days: BookingDay[];
account: TurboselfAccount | ARDAccount;
}

export interface BookingDay {
id: string;
canBook: boolean;
date: Date;
message: string;
booked: boolean;
}
1 change: 1 addition & 0 deletions src/services/shared/ReservationHistory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ export interface ReservationHistory {
amount: number
timestamp: number
currency: string
label: string
}
25 changes: 13 additions & 12 deletions src/services/turboself/balance.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import type { TurboselfAccount } from "@/stores/account/types";
import { balance, host } from "turbawself";
import type { Balance } from "../shared/Balance";

export const getBalance = async (account: TurboselfAccount): Promise<Balance> => {
const b = await balance(account.authentication.auth, account.authentication.session);
const h = await host(account.authentication.auth, account.authentication.session);
export const getBalance = async (account: TurboselfAccount): Promise<Balance[]> => {
const balances = await account.authentication.session.balances;
const currencySymbol = await account.authentication.session.establishment?.currencySymbol;
const lunchPrice = await account.authentication.session.host?.lunchPrice;

return {
amount: b.amount / 100,
currency: "€",
remaining: Math.floor(b.amount / h.lunchPrice)

// since turboself is french, we can assume the currency is always euro.
// note: would need more information to be sure.
};
const result: Balance[] = [];
for (const balance of balances ?? []) {
result.push({
amount: balance.estimatedAmount / 100,
currency: currencySymbol ?? "€",
remaining: Math.floor(balance.estimatedAmount / (lunchPrice ?? 0)),
});
}
return result;
};
34 changes: 34 additions & 0 deletions src/services/turboself/booking.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import type { TurboselfAccount } from "@/stores/account/types";
import type { BookingDay, BookingTerminal } from "../shared/Booking";

export const getBookingWeek = async (account: TurboselfAccount, weekNumber?: number): Promise<BookingTerminal[]> => {
const bookings = await account.authentication.session.getBookings(weekNumber);

return bookings.map((booking) => ({
account,
id: booking.id,
week: booking.week,
from: booking.from,
to: booking.to,
terminalLabel: booking.terminal.name,
days: booking.days.map((day) => ({
id: day.id,
canBook: day.canBook,
date: day.date,
message: day.message,
booked: day.booked,
})),
}));
};

export const bookDay = async (account: TurboselfAccount, id: string, date: Date, booked: boolean): Promise<BookingDay> => {
const bookedDay = await account.authentication.session.bookMeal(id, date.getDay() + 1, booked ? 1 : 0);
console.log(bookedDay);
return {
id: bookedDay.id,
canBook: bookedDay.canBook,
date: bookedDay.date,
message: bookedDay.message,
booked: bookedDay.booked,
};
};
8 changes: 4 additions & 4 deletions src/services/turboself/history.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import type { TurboselfAccount } from "@/stores/account/types";
import type { ReservationHistory } from "../shared/ReservationHistory";
import { summary } from "turbawself";

export const getHistory = async (account: TurboselfAccount): Promise<ReservationHistory[]> => {
const h = await summary(account.authentication.auth, account.authentication.session);
const history = await account.authentication.session.getHistory();

return (h.history ?? []).map((reservation) => ({
return (history ?? []).map((reservation) => ({
timestamp: reservation.date.getTime(),
amount: reservation.amount / 100,
currency: "€"
currency: account.authentication.session.establishment?.currencySymbol ?? "€",
label: reservation.label,
}));
};
6 changes: 6 additions & 0 deletions src/services/turboself/qrcode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import type { TurboselfAccount } from "@/stores/account/types";

export const getQRCode = async (account: TurboselfAccount): Promise<number> => {
const cardNumber = await account.authentication.session.host?.cardNumber;
return cardNumber ?? 0;
};
10 changes: 5 additions & 5 deletions src/services/turboself/reload.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import type { TurboselfAccount } from "@/stores/account/types";
import { login } from "turbawself";
import { authenticateWithCredentials } from "turboself-api";

export const reload = async (account: TurboselfAccount): Promise<TurboselfAccount["authentication"]["auth"]> => {
const auth = { ...account.authentication.auth }; // make sure to make a copy of the object.
await login(auth);
return auth;
export const reload = async (account: TurboselfAccount): Promise<TurboselfAccount["authentication"]["session"]> => {
const auth = { ...account.authentication };
const session = await authenticateWithCredentials(auth.username, auth.password);
return session;
};
9 changes: 5 additions & 4 deletions src/stores/account/types.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type pronote from "pawnote";
import type { Account as PawdirecteAccount, Session as PawdirecteSession } from "pawdirecte";
import type { Session as TSSession, Authentication as TSAuthentication } from "turbawself";
import type { Client as ARDClient } from "pawrd";
import type { Client as ARDClient, Client as PawrdClient } from "pawrd";
import { Client as TurboselfClient } from "turboself-api";
import type ScolengoAPI from "scolengo-api";
import { SkolengoAuthConfig } from "@/services/skolengo/skolengo-types";
import { User as ScolengoAPIUser } from "scolengo-api/types/models/Common";
Expand Down Expand Up @@ -143,8 +143,9 @@ export interface TurboselfAccount extends BaseExternalAccount {
service: AccountService.Turboself
instance: undefined
authentication: {
auth: TSAuthentication
session: TSSession
session: TurboselfClient
username: string
password: string
}
}

Expand Down
Loading