Skip to content

Commit 8f666a2

Browse files
committed
feat: Add calendar and announcement modules with responsive design
- Implemented a calendar component with event handling and Persian date formatting. - Created an announcement module for displaying and copying messages. - Added responsive styles for mobile devices in SCSS files. - Introduced a floating button section for quick access to links and theme toggling. - Developed a footer and header component with theme context support. - Integrated toast notifications for user feedback on actions. - Established constants for events and Persian weekdays. - Enhanced the theme provider for light and dark modes. - Included utility functions for date formatting and number conversion.
1 parent 6eb6e54 commit 8f666a2

67 files changed

Lines changed: 12672 additions & 7364 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.editorconfig

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
root = true
2+
3+
[*]
4+
charset = utf-8
5+
end_of_line = lf
6+
insert_final_newline = true
7+
trim_trailing_whitespace = true
8+
indent_style = space
9+
indent_size = 4
10+
11+
[*.{js,jsx}]
12+
indent_size = 4
13+
insert_final_newline = true
14+
trim_trailing_whitespace = true
15+
16+
[package.json]
17+
[package-lock.json]
18+
[yarn.lock]
19+
[pnpm-lock.yaml]
20+
[*.{yml,yaml}]
21+
[.github/**/*.yml]
22+
[.github/**/*.yaml]
23+
[.github/**/*.json]
24+
[.vscode/**/*.json]
25+
[ci.yml]
26+
[.prettierrc]
27+
indent_size = 2
28+
trim_trailing_whitespace = true
29+
insert_final_newline = true
30+
31+
[*.md]
32+
trim_trailing_whitespace = false
33+
insert_final_newline = true
34+
indent_size = 4
35+
36+
[*.{css,scss,less}]
37+
indent_style = space
38+
indent_size = 4
39+
40+
[*.sh]
41+
indent_style = space
42+
indent_size = 4
43+
end_of_line = lf
44+
insert_final_newline = true
45+
trim_trailing_whitespace = true

.eslintrc.json

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Temp ESLint config for testing only
2+
{
3+
"env": {
4+
"es2021": true,
5+
"node": true,
6+
"jest": true
7+
},
8+
"extends": ["eslint:recommended", "plugin:prettier/recommended"],
9+
"parserOptions": {
10+
"ecmaVersion": "latest",
11+
"sourceType": "module"
12+
},
13+
"rules": {
14+
"no-unused-vars": ["warn", { "argsIgnorePattern": "^_" }],
15+
"no-console": "off",
16+
"quotes": ["error", "double"],
17+
"semi": ["error", "always"],
18+
"prettier/prettier": [
19+
"error",
20+
{
21+
"endOfLine": "auto"
22+
}
23+
]
24+
}
25+
}

.github/CODEOWNERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* @Ali-Sdg90

.github/workflows/ci.yml

Lines changed: 323 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,323 @@
1+
name: React CI/CD (CRA → GitHub Pages)
2+
3+
env:
4+
CI: "true"
5+
IS_ACT: "false"
6+
7+
on:
8+
push:
9+
branches:
10+
- main
11+
- feature/**
12+
pull_request:
13+
branches:
14+
- main
15+
16+
permissions:
17+
contents: write
18+
issues: write
19+
pull-requests: write
20+
21+
concurrency:
22+
group: ${{ github.workflow }}-${{ github.ref }}
23+
cancel-in-progress: true
24+
25+
jobs:
26+
test:
27+
name: 🧪 Test, Lint & Coverage
28+
runs-on: ubuntu-latest
29+
30+
steps:
31+
- name: Checkout
32+
uses: actions/checkout@v4
33+
34+
- name: Setup Node.js 18
35+
uses: actions/setup-node@v4
36+
with:
37+
node-version: 18
38+
cache: npm
39+
cache-dependency-path: package-lock.json
40+
41+
- name: Install deps (CI)
42+
run: npm ci
43+
44+
- name: Prettier check
45+
run: npm run format:check
46+
47+
- name: ESLint
48+
run: npm run lint
49+
50+
- name: Run tests (no watch) with coverage + summary
51+
run: |
52+
npm test --silent -- --coverage | tee test-output.txt
53+
echo "### ✅ Test Results" >> $GITHUB_STEP_SUMMARY
54+
echo '```' >> $GITHUB_STEP_SUMMARY
55+
cat test-output.txt >> $GITHUB_STEP_SUMMARY
56+
echo '```' >> $GITHUB_STEP_SUMMARY
57+
58+
- name: Upload coverage artifact
59+
if: always()
60+
uses: actions/upload-artifact@v4
61+
with:
62+
name: jest-coverage
63+
path: coverage/
64+
if-no-files-found: ignore
65+
66+
release:
67+
name: 🚀 Version & Release
68+
runs-on: ubuntu-latest
69+
needs: test
70+
if: github.ref == 'refs/heads/main'
71+
72+
outputs:
73+
released: ${{ steps.get_tag.outputs.released }}
74+
tag: ${{ steps.get_tag.outputs.tag }}
75+
76+
steps:
77+
- name: Checkout (full history & tags)
78+
uses: actions/checkout@v4
79+
with:
80+
fetch-depth: 0
81+
fetch-tags: true
82+
83+
- name: Setup Node.js 18
84+
uses: actions/setup-node@v4
85+
with:
86+
node-version: 18
87+
cache: npm
88+
cache-dependency-path: package-lock.json
89+
90+
- name: Install deps (CI)
91+
run: npm ci
92+
93+
- name: Semantic Release
94+
id: semantic_release
95+
if: ${{ env.IS_ACT != 'true' }}
96+
uses: cycjimmy/semantic-release-action@v4
97+
with:
98+
extra_plugins: |
99+
@semantic-release/changelog
100+
@semantic-release/git
101+
@semantic-release/github
102+
env:
103+
GITHUB_TOKEN: ${{ secrets.GH_PAT }}
104+
105+
- name: Get created tag
106+
id: get_tag
107+
if: ${{ always() }}
108+
run: |
109+
if [ "${IS_ACT}" = "true" ]; then
110+
echo "tag=local-test" >> $GITHUB_OUTPUT
111+
echo "released=true" >> $GITHUB_OUTPUT
112+
else
113+
git fetch --tags || true
114+
TAGS=$(git tag --points-at HEAD || true)
115+
TAG=$(echo "$TAGS" | head -n1 | tr -d '\r\n')
116+
if [ -n "$TAG" ]; then
117+
echo "tag=$TAG" >> $GITHUB_OUTPUT
118+
echo "released=true" >> $GITHUB_OUTPUT
119+
else
120+
echo "tag=" >> $GITHUB_OUTPUT
121+
echo "released=false" >> $GITHUB_OUTPUT
122+
fi
123+
fi
124+
125+
build:
126+
name: 🏗️ Build (CRA)
127+
runs-on: ubuntu-latest
128+
needs: release
129+
if: needs.release.outputs.released == 'true'
130+
131+
steps:
132+
- name: Checkout
133+
uses: actions/checkout@v4
134+
135+
- name: Setup Node.js 18
136+
uses: actions/setup-node@v4
137+
with:
138+
node-version: 18
139+
cache: npm
140+
cache-dependency-path: package-lock.json
141+
142+
- name: Install deps (CI)
143+
run: npm ci
144+
145+
- name: Build
146+
run: npm run build
147+
148+
- name: Add SPA 404 fallback
149+
run: cp build/index.html build/404.html
150+
151+
- name: Upload build artifact
152+
uses: actions/upload-artifact@v4
153+
with:
154+
name: react-build
155+
path: build/
156+
if-no-files-found: error
157+
158+
deploy:
159+
name: 🚀 Deploy to GitHub Pages
160+
runs-on: ubuntu-latest
161+
needs: build
162+
if: needs.release.outputs.released == 'true'
163+
164+
steps:
165+
- name: Download build artifact
166+
if: ${{ env.IS_ACT != 'true' }}
167+
uses: actions/download-artifact@v4
168+
with:
169+
name: react-build
170+
path: build
171+
172+
- name: Deploy using gh-pages action
173+
if: ${{ env.IS_ACT != 'true' }}
174+
uses: peaceiris/actions-gh-pages@v3
175+
with:
176+
github_token: ${{ secrets.GITHUB_TOKEN }}
177+
publish_dir: build
178+
publish_branch: gh-pages
179+
user_name: "github-actions[bot]"
180+
user_email: "github-actions[bot]@users.noreply.github.com"
181+
182+
notify-release:
183+
name: 📢 Telegram Success Notification
184+
runs-on: ubuntu-latest
185+
needs: [release, deploy]
186+
if: needs.release.outputs.released == 'true'
187+
188+
steps:
189+
- name: Checkout (full history & tags)
190+
uses: actions/checkout@v4
191+
with:
192+
fetch-depth: 0
193+
fetch-tags: true
194+
195+
- name: Send Telegram notification
196+
env:
197+
IS_ACT: ${{ env.IS_ACT }}
198+
TELEGRAM_BOT_TOKEN: ${{ secrets.TELEGRAM_BOT_TOKEN }}
199+
TELEGRAM_CHAT_ID: ${{ secrets.TELEGRAM_CHAT_ID }}
200+
ACTION_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
201+
RELEASE_TAG: ${{ needs.release.outputs.tag }}
202+
GITHUB_ACTOR: ${{ github.actor }}
203+
run: |
204+
escape_html() {
205+
printf '%s' "$1" | sed -e 's/&/\&amp;/g' -e 's/</\&lt;/g' -e 's/>/\&gt;/g' -e 's/"/\&quot;/g'
206+
}
207+
208+
if [ "${IS_ACT}" = "true" ]; then
209+
TAG="local-test"
210+
else
211+
TAG="${RELEASE_TAG}"
212+
fi
213+
214+
LAST_AUTHOR="${GITHUB_ACTOR}"
215+
AUTHOR_LINK="https://github.com/${LAST_AUTHOR}"
216+
DATE=$(date -u +"%Y-%m-%d %H:%M:%S UTC")
217+
218+
eTAG=$(escape_html "$TAG")
219+
eAuthor=$(escape_html "$LAST_AUTHOR")
220+
eAuthorLink=$(escape_html "$AUTHOR_LINK")
221+
eActionRun=$(escape_html "$ACTION_RUN_URL")
222+
eDate=$(escape_html "$DATE")
223+
224+
printf -v MESSAGE '%s\n%s\n%s\n%s\n%s' \
225+
"🚀 <b>New release published!</b>" \
226+
"🏷️ <b>Version:</b> ${eTAG}" \
227+
"👤 <b>Author:</b> <a href=\"${eAuthorLink}\">${eAuthor}</a>" \
228+
"🕓 <b>Date:</b> ${eDate}" \
229+
"🔗 <a href=\"${eActionRun}\">View GitHub Action Run</a>"
230+
231+
RESPONSE="$(curl -s -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \
232+
--data-urlencode "chat_id=${TELEGRAM_CHAT_ID}" \
233+
--data-urlencode "text=${MESSAGE}" \
234+
-d "parse_mode=HTML" \
235+
-d "disable_web_page_preview=true" \
236+
-w "\n%{http_code}")"
237+
238+
HTTP_CODE="$(echo "$RESPONSE" | tail -n1)"
239+
BODY="$(echo "$RESPONSE" | sed '$d')"
240+
241+
if [ "$HTTP_CODE" != "200" ] || ! echo "$BODY" | grep -q '"ok":true'; then
242+
echo "❌ Telegram API error. HTTP=$HTTP_CODE BODY=$BODY"
243+
exit 1
244+
fi
245+
246+
echo "✅ Telegram notification sent."
247+
248+
notify-error:
249+
name: 📢 Telegram Error Notification
250+
runs-on: ubuntu-latest
251+
needs: [test, release, build, deploy]
252+
if: ${{ failure() }}
253+
254+
steps:
255+
- name: Checkout
256+
uses: actions/checkout@v4
257+
with:
258+
fetch-depth: 0
259+
260+
- name: Send Telegram error notification
261+
env:
262+
TELEGRAM_BOT_TOKEN: ${{ secrets.TELEGRAM_BOT_TOKEN }}
263+
TELEGRAM_CHAT_ID: ${{ secrets.TELEGRAM_CHAT_ID }}
264+
GITHUB_ACTOR: ${{ github.actor }}
265+
GITHUB_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
266+
run: |
267+
LAST_AUTHOR="${GITHUB_ACTOR}"
268+
AUTHOR_LINK="https://github.com/${LAST_AUTHOR}"
269+
FAILED_STEPS=()
270+
271+
if [ "${{ needs.test.result }}" = "failure" ]; then
272+
FAILED_STEPS+=("Tests")
273+
fi
274+
if [ "${{ needs.release.result }}" = "failure" ]; then
275+
FAILED_STEPS+=("Release")
276+
fi
277+
if [ "${{ needs.build.result }}" = "failure" ]; then
278+
FAILED_STEPS+=("Build")
279+
fi
280+
if [ "${{ needs.deploy.result }}" = "failure" ]; then
281+
FAILED_STEPS+=("Deploy")
282+
fi
283+
284+
if [ ${#FAILED_STEPS[@]} -eq 0 ]; then
285+
echo "No failed steps detected. Exiting."
286+
exit 0
287+
fi
288+
289+
FAILED_LIST=$(IFS=', '; echo "${FAILED_STEPS[*]}")
290+
291+
escape_html() {
292+
printf '%s' "$1" | sed -e 's/&/\&amp;/g' -e 's/</\&lt;/g' -e 's/>/\&gt;/g' -e 's/"/\&quot;/g'
293+
}
294+
295+
eFailedList=$(escape_html "$FAILED_LIST")
296+
eActor=$(escape_html "$LAST_AUTHOR")
297+
eAuthorLink=$(escape_html "$AUTHOR_LINK")
298+
eRunURL=$(escape_html "$GITHUB_RUN_URL")
299+
eDate=$(escape_html "$(date -u +"%Y-%m-%d %H:%M:%S UTC")")
300+
301+
printf -v MESSAGE '%s\n%s\n%s\n%s\n%s' \
302+
"❌ <b>Pipeline Error Detected</b>" \
303+
"⚠️ <b>Failed Steps:</b> ${eFailedList}" \
304+
"👤 <b>Triggered by:</b> <a href=\"${eAuthorLink}\">${eActor}</a>" \
305+
"🕓 <b>Date:</b> ${eDate}" \
306+
"🔗 <a href=\"${eRunURL}\">View GitHub Action Run</a>"
307+
308+
RESPONSE="$(curl -s -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \
309+
--data-urlencode "chat_id=${TELEGRAM_CHAT_ID}" \
310+
--data-urlencode "text=${MESSAGE}" \
311+
-d "parse_mode=HTML" \
312+
-d "disable_web_page_preview=true" \
313+
-w "\n%{http_code}")"
314+
315+
HTTP_CODE="$(echo "$RESPONSE" | tail -n1)"
316+
BODY="$(echo "$RESPONSE" | sed '$d')"
317+
318+
if [ "$HTTP_CODE" != "200" ] || ! echo "$BODY" | grep -q '"ok":true'; then
319+
echo "❌ Telegram API error. HTTP=$HTTP_CODE BODY=$BODY"
320+
exit 1
321+
fi
322+
323+
echo "✅ Telegram error notification sent."

0 commit comments

Comments
 (0)