Skip to content

Commit 5cb9a20

Browse files
Update alias and API redirects, modify sitemap last modified dates, and enhance profile localization with referral program details.
1 parent 001e56f commit 5cb9a20

File tree

8 files changed

+212
-10
lines changed

8 files changed

+212
-10
lines changed

public/alias-redirects.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

public/locales/en/profile.json

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,5 +175,14 @@
175175
"months": "months",
176176
"month": "month",
177177
"expired": "Expired",
178-
"no-subscriptions": "There are no subscriptions to show yet, subscribe to a cohort and get it immediately"
178+
"no-subscriptions": "There are no subscriptions to show yet, subscribe to a cohort and get it immediately",
179+
"referral-program": "Referral Program",
180+
"referral-coupon": "Your Referral Coupon",
181+
"copy-coupon": "Copy Coupon",
182+
"coupon-copied": "Coupon copied to clipboard!",
183+
"how-it-works": "How it works:",
184+
"referral-step-1": "1. Share your coupon code with friends and family",
185+
"referral-step-2": "2. When someone uses your coupon and makes a payment for self-paced programs on 4Geeks.com, you'll get a 10% discount on your next payment",
186+
"referral-step-3": "3. The more people use your coupon, the more discounts you'll receive!",
187+
"referral-step-4": "4. This referral program only applies to self-paced programs at 4Geeks.com"
179188
}

public/locales/es/profile.json

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,5 +175,14 @@
175175
"months": "meses",
176176
"month": "mes",
177177
"expired": "Expirado",
178-
"no-subscriptions": "Todavía no hay suscripciones para mostrar, suscríbete a una cohorte y obténgala de inmediato"
178+
"no-subscriptions": "Todavía no hay suscripciones para mostrar, suscríbete a una cohorte y obténgala de inmediato",
179+
"referral-program": "Programa de Referidos",
180+
"referral-coupon": "Tu Cupón de Referido",
181+
"copy-coupon": "Copiar Cupón",
182+
"coupon-copied": "¡Cupón copiado al portapapeles!",
183+
"how-it-works": "Cómo funciona:",
184+
"referral-step-1": "1. Comparte tu código de cupón con amigos y familiares",
185+
"referral-step-2": "2. Cuando alguien use tu cupón y haga un pago por programas autodidactas en 4Geeks.com, obtendrás un 10% de descuento en tu próximo pago",
186+
"referral-step-3": "3. ¡Mientras más personas usen tu cupón, más descuentos recibirás!",
187+
"referral-step-4": "4. Este programa de referidos solo aplica para programas a tu propio ritmo en 4Geeks.com"
179188
}

public/redirects-from-api.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

public/sitemap.xml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,26 @@
22
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
33
<sitemap>
44
<loc>https://4geeks.com/pages-sitemap.xml</loc>
5-
<lastmod>2025-04-04T14:09:09.646Z</lastmod>
5+
<lastmod>2025-05-27T18:55:20.586Z</lastmod>
66
</sitemap>
77
<sitemap>
88
<loc>https://4geeks.com/howto-sitemap.xml</loc>
9-
<lastmod>2025-04-04T14:09:09.646Z</lastmod>
9+
<lastmod>2025-05-27T18:55:20.586Z</lastmod>
1010
</sitemap>
1111
<sitemap>
1212
<loc>https://4geeks.com/lessons-sitemap.xml</loc>
13-
<lastmod>2025-04-04T14:09:09.646Z</lastmod>
13+
<lastmod>2025-05-27T18:55:20.586Z</lastmod>
1414
</sitemap>
1515
<sitemap>
1616
<loc>https://4geeks.com/projects-sitemap.xml</loc>
17-
<lastmod>2025-04-04T14:09:09.646Z</lastmod>
17+
<lastmod>2025-05-27T18:55:20.586Z</lastmod>
1818
</sitemap>
1919
<sitemap>
2020
<loc>https://4geeks.com/exercises-sitemap.xml</loc>
21-
<lastmod>2025-04-04T14:09:09.646Z</lastmod>
21+
<lastmod>2025-05-27T18:55:20.586Z</lastmod>
2222
</sitemap>
2323
<sitemap>
2424
<loc>https://4geeks.com/technologies-sitemap.xml</loc>
25-
<lastmod>2025-04-04T14:09:09.646Z</lastmod>
25+
<lastmod>2025-05-27T18:55:20.586Z</lastmod>
2626
</sitemap>
2727
</sitemapindex>

src/components/Profile/Information.jsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import getCroppedImg from '../../utils/cropImage';
1313
import Icon from '../Icon';
1414
import useUploadFileInChunks from '../../hooks/useUploadFileInChunks';
1515
import useCustomToast from '../../hooks/useCustomToast';
16+
import ReferralProgram from './ReferralProgram';
1617

1718
function Information() {
1819
const { t } = useTranslation('profile');
@@ -241,6 +242,9 @@ function Information() {
241242
</Avatar>
242243
<ProfileForm />
243244
</Box>
245+
<Box mt="38px">
246+
<ReferralProgram />
247+
</Box>
244248
</>
245249
);
246250
}
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
import { Box, Button, Input, InputGroup, InputRightElement } from '@chakra-ui/react';
2+
import useTranslation from 'next-translate/useTranslation';
3+
import { useEffect, useState } from 'react';
4+
import Text from '../Text';
5+
import useStyle from '../../hooks/useStyle';
6+
import bc from '../../services/breathecode';
7+
import Icon from '../Icon';
8+
import useCustomToast from '../../hooks/useCustomToast';
9+
10+
function ReferralProgram() {
11+
const { t } = useTranslation('profile');
12+
const { borderColor2, hexColor, lightColor } = useStyle();
13+
const { createToast } = useCustomToast({ toastId: 'referral-coupon' });
14+
const [coupon, setCoupon] = useState('');
15+
const [couponData, setCouponData] = useState(null);
16+
const [isLoading, setIsLoading] = useState(true);
17+
18+
useEffect(() => {
19+
const fetchCoupon = async () => {
20+
try {
21+
const response = await bc.payment().getMyCoupon();
22+
if (response?.data?.length > 0) {
23+
const couponInfo = response.data[0];
24+
setCoupon(couponInfo?.slug || '');
25+
setCouponData(couponInfo);
26+
}
27+
} catch (error) {
28+
console.error('Error fetching referral coupon:', error);
29+
} finally {
30+
setIsLoading(false);
31+
}
32+
};
33+
34+
fetchCoupon();
35+
}, []);
36+
37+
const copyToClipboard = async () => {
38+
try {
39+
await navigator.clipboard.writeText(coupon);
40+
createToast({
41+
position: 'top',
42+
title: t('coupon-copied'),
43+
status: 'success',
44+
duration: 3000,
45+
isClosable: true,
46+
});
47+
} catch (error) {
48+
console.error('Failed to copy coupon:', error);
49+
}
50+
};
51+
52+
if (isLoading) {
53+
return (
54+
<Box width="100%" height="auto" borderRadius="17px" border="1px solid" borderColor={borderColor2} p="30px">
55+
<Text fontSize="15px" fontWeight="700" pb="18px">
56+
{t('referral-program')}
57+
</Text>
58+
<Text fontSize="14px" color="gray.500">
59+
Loading...
60+
</Text>
61+
</Box>
62+
);
63+
}
64+
65+
if (!coupon) {
66+
return null;
67+
}
68+
69+
const getDiscountText = () => {
70+
if (!couponData?.discount_value || !couponData?.discount_type) return '';
71+
72+
if (couponData.discount_type === 'PERCENT_OFF') {
73+
const percentage = Math.round(couponData.discount_value * 100);
74+
return `${percentage}% OFF for friends and family`;
75+
}
76+
77+
if (couponData.discount_type === 'FIXED_PRICE') {
78+
return `$${couponData.discount_value} OFF for friends and family`;
79+
}
80+
81+
return '';
82+
};
83+
84+
return (
85+
<>
86+
<Text fontSize="15px" fontWeight="700" pb="18px">
87+
{t('referral-program')}
88+
</Text>
89+
<Box width="100%" height="auto" borderRadius="17px" border="1px solid" borderColor={borderColor2} p="30px">
90+
<Box display="flex" flexDirection="column" gridGap="20px">
91+
<Box>
92+
<Box display="flex" justifyContent="space-between" alignItems="center" pb="8px">
93+
<Text fontSize="14px" fontWeight="600">
94+
{t('referral-coupon')}
95+
</Text>
96+
{getDiscountText() && (
97+
<Box borderRadius="4px" padding="5px 8px" background="green.50">
98+
<Text color="green.500" fontWeight="700" fontSize="12px">
99+
{getDiscountText()}
100+
</Text>
101+
</Box>
102+
)}
103+
</Box>
104+
<InputGroup size="md" width="fit-content" maxWidth="300px">
105+
<Input
106+
value={coupon}
107+
isReadOnly
108+
color={lightColor}
109+
borderColor="gray.default"
110+
borderRadius="3px"
111+
height="50px"
112+
width="fit-content"
113+
minWidth="200px"
114+
pr="50px"
115+
cursor="pointer"
116+
onClick={copyToClipboard}
117+
_focus={{
118+
borderColor: hexColor.blueDefault,
119+
boxShadow: `0 0 0 1px ${hexColor.blueDefault}`,
120+
}}
121+
_hover={{
122+
borderColor: hexColor.blueDefault,
123+
}}
124+
/>
125+
<InputRightElement width="40px" height="50px" display="flex" alignItems="center" justifyContent="center">
126+
<Button
127+
size="sm"
128+
variant="solid"
129+
background="gray.300"
130+
color="gray.800"
131+
_hover={{
132+
background: 'gray.400',
133+
color: 'gray.900',
134+
}}
135+
_dark={{
136+
background: 'gray.500',
137+
color: 'gray.100',
138+
_hover: {
139+
background: 'gray.400',
140+
color: 'white',
141+
},
142+
}}
143+
onClick={copyToClipboard}
144+
minWidth="auto"
145+
padding="6px"
146+
height="32px"
147+
>
148+
<Icon icon="copy" width="16px" height="16px" />
149+
</Button>
150+
</InputRightElement>
151+
</InputGroup>
152+
</Box>
153+
154+
<Box>
155+
<Text fontSize="14px" fontWeight="600" pb="12px">
156+
{t('how-it-works')}
157+
</Text>
158+
<Box display="flex" flexDirection="column" gridGap="8px">
159+
<Text fontSize="12px" color="gray.600" lineHeight="1.5">
160+
{t('referral-step-1')}
161+
</Text>
162+
<Text fontSize="12px" color="gray.600" lineHeight="1.5">
163+
{t('referral-step-2')}
164+
</Text>
165+
<Text fontSize="12px" color="gray.600" lineHeight="1.5">
166+
{t('referral-step-3')}
167+
</Text>
168+
<Text fontSize="12px" color="gray.600" lineHeight="1.5">
169+
{t('referral-step-4')}
170+
</Text>
171+
</Box>
172+
</Box>
173+
</Box>
174+
</Box>
175+
</>
176+
);
177+
}
178+
179+
export default ReferralProgram;

src/services/breathecode.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,7 @@ const breathecode = {
387387
getEventTypeSet: (eventTypeSetId) => axios.get(`${url}/eventtypeset/${eventTypeSetId}`),
388388
events: () => axios.get(`${host}/events/me?online_event=true${parseQuerys(query, true)}`),
389389
getBlockedServices: () => axios.get(`${url}/me/service/blocked${qs}`),
390+
getMyCoupon: () => axios.get(`${url}/me/coupon${qs}`),
390391
};
391392
},
392393
events: (query = {}) => {

0 commit comments

Comments
 (0)