كيفية بناء تطبيق طقس باستخدام React وReact Hooks خطوة بخطوة

دقائق القراءة: 10

مقدمة: لماذا يُعد بناء تطبيق طقس باستخدام React مشروعاً مثالياً؟

يُعد تطبيق الطقس من المشاريع العملية الممتازة لفهم أساسيات تطوير الواجهات الحديثة، لأنه يجمع بين أكثر من مفهوم مهم في وقت واحد، مثل إدارة الحالة، استدعاء البيانات من واجهات API خارجية، التعامل مع الموقع الجغرافي للمستخدم، وعرض المعلومات بأسلوب واضح وجذاب. ومع استخدام React وميزة React Hooks، يصبح بناء هذا النوع من التطبيقات أكثر مرونة وتنظيماً.

في هذا الدليل، سنتعلم كيفية إنشاء تطبيق طقس يعرض حالة الطقس الحالية اعتماداً على موقع المستخدم، مع استخدام مكتبات مساعدة لتحسين التصميم وتنسيق الوقت والتاريخ، مع الحفاظ على بنية نظيفة وقابلة للتطوير.

واجهة توضيحية لمشروع تطبيق طقس باستخدام React وReact Hooks

تجهيز البيئة: تثبيت Node.js وnpm

قبل البدء في إنشاء المشروع، نحتاج إلى بيئة تشغيل مناسبة لتطبيقات JavaScript. هنا يأتي دور Node.js، وهو بيئة تشغيل تتيح تنفيذ شيفرات JavaScript خارج المتصفح، كما يُعد أساساً لعدد كبير من أدوات التطوير الحديثة.

أما npm فهو مدير الحزم المدمج مع Node.js، ويُستخدم لتثبيت المكتبات والأدوات التي يحتاجها المشروع.

خطوات التثبيت والتحقق

  1. توجه إلى الموقع الرسمي: https://nodejs.org/en/
  2. نزّل النسخة المناسبة لنظامك.
  3. بعد اكتمال التثبيت، افتح الطرفية Terminal أو موجه الأوامر Command Prompt.
  4. نفّذ الأمر التالي للتحقق من نجاح التثبيت:
node -v

إذا ظهر رقم إصدار، فهذا يعني أن Node.js يعمل بشكل صحيح.

إنشاء مشروع React جديد

لإنشاء التطبيق بسرعة، يمكن استخدام أداة create-react-app التي توفر هيكلاً جاهزاً لبدء التطوير.

npx create-react-app my-weather-app

بعد اكتمال تثبيت الحزم، ادخل إلى مجلد المشروع ثم شغّل التطبيق:

cd my-weather-app
npm start

عندها ستظهر لك الواجهة الافتراضية الخاصة بـReact.

القالب الافتراضي الأولي بعد إنشاء مشروع React جديدملف App.js في مشروع React قبل التعديل

تنظيف القالب الافتراضي

لا نحتاج إلى جميع العناصر المبدئية الموجودة داخل ملف App.js. لذلك يمكن حذف المحتوى داخل وسم div الرئيسي، وإزالة استيراد الشعار الافتراضي. بعد ذلك ستظهر شاشة فارغة، وهذا أمر طبيعي لأنه يمثل نقطة انطلاق نظيفة للمشروع.

ملف App.js بعد تنظيف القالب الافتراضي في React

تثبيت المكتبات المطلوبة للمشروع

لجعل التطبيق أكثر أناقة وسهولة في العرض، سنستخدم بعض الحزم الخارجية. أهم هذه الحزم:

  • semantic-ui-react لبناء عناصر واجهة جاهزة.
  • semantic-ui-css لتوفير أنماط المكتبة.
  • moment لتنسيق التاريخ والوقت بسهولة.

تثبيت مكتبة Semantic UI

npm install semantic-ui-react semantic-ui-css

بعد التثبيت، افتح ملف index.js وأضف السطر التالي:

import 'semantic-ui-css/semantic.min.css'

تثبيت مكتبة moment

npm install moment --save

يمكنك مراجعة ملف package.json لمتابعة جميع الحزم التي تم تثبيتها داخل المشروع.

ملف package.json بعد تثبيت الحزم اللازمة لتطبيق الطقس

الحصول على بيانات الطقس عبر OpenWeatherMap API

لكي يعمل التطبيق فعلياً، نحتاج إلى مصدر خارجي يزوّدنا ببيانات الطقس. من أشهر هذه الخدمات منصة OpenWeatherMap، وهي توفر واجهات API متعددة تشمل الطقس الحالي والتوقعات المستقبلية وغيرها.

خطوات إعداد الحساب والمفتاح البرمجي

  1. أنشئ حساباً عبر الرابط: https://home.openweathermap.org/users/sign_up
  2. بعد تسجيل الدخول، انتقل إلى قسم API.
  3. ستجد عدة نقاط وصول Endpoints مثل بيانات الطقس الحالية والتوقعات الساعية واليومية.
  4. من قائمة الحساب، ادخل إلى قسم My API keys.
  5. أنشئ مفتاحاً جديداً إذا لم يكن لديك واحد بالفعل.

لوحة OpenWeatherMap التي تعرض خيارات واجهة API الخاصة بالطقس

إنشاء ملف المتغيرات البيئية .env

داخل المجلد الرئيسي للمشروع، أنشئ ملفاً باسم .env ثم أضف القيم التالية:

REACT_APP_API_URL='https://api.openweathermap.org/data/2.5'
REACT_APP_API_KEY=YOUR_API_KEY_HERE
REACT_APP_ICON_URL='https://openweathermap.org/img/w'

استبدل القيمة YOUR_API_KEY_HERE بمفتاح API الحقيقي الخاص بك. استخدام ملف .env يساعد على تنظيم الإعدادات وفصلها عن منطق التطبيق.

فهم React Hooks واستخدامها في المشروع

توفر React Hooks وسيلة حديثة لإدارة الحالة والتعامل مع دورة حياة المكونات الوظيفية دون الحاجة إلى المكونات الصنفية Class Components. في هذا المشروع سنعتمد على:

  • useState لتخزين القيم المتغيرة مثل خط العرض وخط الطول وبيانات الطقس.
  • useEffect لتنفيذ الأوامر عند تحميل الصفحة أو تحديث القيم المرتبطة بها.

استيراد الأدوات الأساسية

import React, { useEffect, useState } from "react";

إنشاء الحالات الأساسية

const [lat, setLat] = useState([]);
const [long, setLong] = useState([]);

هنا نُعرّف حالتين لتخزين خط العرض latitude وخط الطول longitude الخاصين بموقع المستخدم.

استخدام useEffect للحصول على الموقع الجغرافي

useEffect(() => {
  navigator.geolocation.getCurrentPosition(function (position) {
    setLat(position.coords.latitude);
    setLong(position.coords.longitude);
  });

  console.log("Latitude is:", lat);
  console.log("Longitude is:", long);
}, [lat, long]);

تعتمد هذه الخطوة على navigator.geolocation لجلب إحداثيات المستخدم بعد الحصول على إذنه. ثم يتم تخزين هذه القيم عبر الدالتين setLat وsetLong.

الشكل الحالي لملف App.js

import './App.css';
import React, { useEffect, useState } from "react";

export default function App() {
  const [lat, setLat] = useState([]);
  const [long, setLong] = useState([]);

  useEffect(() => {
    navigator.geolocation.getCurrentPosition(function (position) {
      setLat(position.coords.latitude);
      setLong(position.coords.longitude);
    });

    console.log("Latitude is:", lat);
    console.log("Longitude is:", long);
  }, [lat, long]);

  return (
    <div className="App"></div>
  );
}

بعد تنفيذ ذلك، ستتمكن من رؤية الإحداثيات في وحدة التحكم Console.

Latitude is: 25.5922166
Longitude is: 85.12761069999999

جلب بيانات الطقس وفقاً للموقع الحالي

بعد الحصول على الموقع الجغرافي، ننتقل إلى الخطوة الأهم: جلب حالة الطقس الحالية باستخدام fetch وربط الإحداثيات بواجهة OpenWeatherMap API.

إنشاء حالة لتخزين بيانات الطقس

const [data, setData] = useState([]);

تنفيذ طلب fetch

await fetch(`${process.env.REACT_APP_API_URL}/weather/?lat=${lat}&lon=${long}&units=metric&APPID=${process.env.REACT_APP_API_KEY}`)
  .then(res => res.json())
  .then(result => {
    setData(result);
    console.log(result);
  });

في هذا السطر، نستخدم:

  • process.env.REACT_APP_API_URL للوصول إلى عنوان الواجهة البرمجية.
  • process.env.REACT_APP_API_KEY لاستخدام المفتاح المخزن في ملف .env.
  • lat وlong لتمرير إحداثيات المستخدم.
  • units=metric للحصول على درجات الحرارة بالمقياس المئوي.

بيانات الطقس المسترجعة من OpenWeatherMap داخل وحدة التحكم

النسخة المحدثة من ملف App.js

import './App.css';
import React, { useEffect, useState } from "react";
import Weather from './components/weather';

export default function App() {
  const [lat, setLat] = useState([]);
  const [long, setLong] = useState([]);
  const [data, setData] = useState([]);

  useEffect(() => {
    const fetchData = async () => {
      navigator.geolocation.getCurrentPosition(function (position) {
        setLat(position.coords.latitude);
        setLong(position.coords.longitude);
      });

      await fetch(`${process.env.REACT_APP_API_URL}/weather/?lat=${lat}&lon=${long}&units=metric&APPID=${process.env.REACT_APP_API_KEY}`)
        .then(res => res.json())
        .then(result => {
          setData(result);
          console.log(result);
        });
    };

    fetchData();
  }, [lat, long]);

  return (
    <div className="App"></div>
  );
}

إنشاء مكوّن عرض الطقس Weather Component

حتى نحافظ على تنظيم المشروع، من الأفضل فصل واجهة عرض بيانات الطقس في مكوّن مستقل. داخل مجلد src، أنشئ مجلداً باسم components ثم ملفاً باسم weather.js.

استدعاء المكوّن داخل App.js

import './App.css';
import React, { useEffect, useState } from "react";
import Weather from './components/weather';

export default function App() {
  const [lat, setLat] = useState([]);
  const [long, setLong] = useState([]);
  const [data, setData] = useState([]);

  useEffect(() => {
    const fetchData = async () => {
      navigator.geolocation.getCurrentPosition(function (position) {
        setLat(position.coords.latitude);
        setLong(position.coords.longitude);
      });

      await fetch(`${process.env.REACT_APP_API_URL}/weather/?lat=${lat}&lon=${long}&units=metric&APPID=${process.env.REACT_APP_API_KEY}`)
        .then(res => res.json())
        .then(result => {
          setData(result);
          console.log(result);
        });
    };

    fetchData();
  }, [lat, long]);

  return (
    <div className="App">
      {(typeof data.main !== 'undefined') ? (
        <Weather weatherData={data} />
      ) : (
        <div></div>
      )}
    </div>
  );
}

التحقق من أن data.main ليس undefined خطوة ضرورية، لأن جلب البيانات يتم بشكل غير متزامن async. ولو حاولت الواجهة الوصول إلى خصائص غير موجودة قبل اكتمال الطلب، فسيظهر خطأ أثناء التصيير.

خطأ undefined الناتج عن محاولة عرض بيانات قبل اكتمال طلب API

تمرير البيانات عبر Props بين المكونات

في React، تُستخدم Props لنقل البيانات من المكوّن الأب إلى المكوّن الابن. في مشروعنا:

  • المكوّن الأب هو App.js.
  • المكوّن الابن هو weather.js.

تمرير البيانات يتم بهذا الشكل:

<Weather weatherData={data} />

واستقبالها داخل الملف الآخر يتم على النحو التالي:

import React from 'react';
import './styles.css';
import { Card } from 'semantic-ui-react';

const CardExampleCard = ({ weatherData }) => (
  <Card>
    <Card.Content>
      <Card.Header className="header">{weatherData.name}</Card.Header>
    </Card.Content>
  </Card>
);

export default CardExampleCard;

في هذه المرحلة، سيظهر اسم المدينة بناءً على موقع المستخدم.

عرض اسم المدينة داخل مكون الطقس في React

عرض تفاصيل الطقس الأساسية داخل الواجهة

بعد التأكد من وصول البيانات بنجاح، يمكن توسيع المكوّن ليعرض معلومات إضافية مثل درجة الحرارة، وقت الشروق والغروب، والوصف العام للحالة الجوية.

import React from 'react';
import './styles.css';
import { Card } from 'semantic-ui-react';

const CardExampleCard = ({ weatherData }) => (
  <Card>
    <Card.Content>
      <Card.Header className="header">City Name: {weatherData.name}</Card.Header>
      <p>Temprature: {weatherData.main.temp}</p>
      <p>Sunrise: {weatherData.sys.sunrise}</p>
      <p>Sunset: {weatherData.sys.sunset}</p>
      <p>Description: {weatherData.weather[0].description}</p>
    </Card.Content>
  </Card>
);

export default CardExampleCard;

عرض بيانات الطقس الأساسية مثل الحرارة والشروق والغروب والوصف

كما يمكنك إضافة حقول أخرى مثل:

  • الرطوبة Humidity
  • سرعة الرياح Wind Speed
  • مدى الرؤية Visibility
  • الضغط الجوي Pressure

تنسيق البيانات لتحسين القراءة وتجربة الاستخدام

عرض البيانات الخام كما تأتي من API ليس الأفضل دائماً، لذلك من المهم تحويلها إلى صيغة مفهومة للمستخدم.

إظهار الحرارة بالمقياس المئوي

يمكنك إضافة الرمز °C إلى درجة الحرارة حتى تصبح أكثر وضوحاً.

تحويل وقت الشروق والغروب إلى توقيت محلي

import React from 'react';
import './styles.css';
import { Card } from 'semantic-ui-react';

const CardExampleCard = ({ weatherData }) => (
  <Card>
    <Card.Content>
      <Card.Header className="header">City Name: {weatherData.name}</Card.Header>
      <p>Temprature: {weatherData.main.temp} &deg; C</p>
      <p>Sunrise: {new Date(weatherData.sys.sunrise * 1000).toLocaleTimeString('en-IN')}</p>
      <p>Sunset: {new Date(weatherData.sys.sunset * 1000).toLocaleTimeString('en-IN')}</p>
      <p>Description: {weatherData.weather[0].main}</p>
      <p>Humidity: {weatherData.main.humidity} %</p>
    </Card.Content>
  </Card>
);

export default CardExampleCard;

تُعاد قيم الشروق والغروب من API بصيغة Unix Timestamp، لذلك نضربها في 1000 ثم نحوّلها إلى وقت محلي مفهوم.

إضافة اليوم والتاريخ باستخدام moment

import moment from 'moment';

<p>Day: {moment().format('dddd')}</p>
<p>Date: {moment().format('LL')}</p>

تسهل مكتبة moment عرض التاريخ واليوم الحاليين بصيغة جاهزة وسلسة.

الشكل المحدث لملف weather.js

import React from 'react';
import './styles.css';
import { Card } from 'semantic-ui-react';
import moment from 'moment';

const CardExampleCard = ({ weatherData }) => (
  <Card>
    <Card.Content>
      <Card.Header className="header">City Name: {weatherData.name}</Card.Header>
      <p>Temprature: {weatherData.main.temp} &deg; C</p>
      <p>Sunrise: {new Date(weatherData.sys.sunrise * 1000).toLocaleTimeString('en-IN')}</p>
      <p>Sunset: {new Date(weatherData.sys.sunset * 1000).toLocaleTimeString('en-IN')}</p>
      <p>Description: {weatherData.weather[0].main}</p>
      <p>Humidity: {weatherData.main.humidity} %</p>
      <p>Day: {moment().format('dddd')}</p>
      <p>Date: {moment().format('LL')}</p>
    </Card.Content>
  </Card>
);

export default CardExampleCard;

واجهة تطبيق الطقس بعد تنسيق التاريخ والوقت وإضافة مزيد من البيانات

تحسين تصميم الواجهة باستخدام CSS

بعد اكتمال منطق التطبيق، تأتي مرحلة التحسين البصري. الهدف هنا ليس الجمال فقط، بل أيضاً تسهيل قراءة البيانات وجعل الواجهة أكثر احترافية.

تحديث هيكل المكوّن

import React from 'react';
import './styles.css';
import moment from 'moment';

const CardExampleCard = ({ weatherData }) => (
  <div className="main">
    <p className="header">{weatherData.name}</p>
    <div>
      <p className="day">Day: {moment().format('dddd')}</p>
    </div>
    <div>
      <p className="temp">Temprature: {weatherData.main.temp} &deg; C</p>
    </div>
  </div>
);

export default CardExampleCard;

تنسيق ملف styles.css

@import url('https://fonts.googleapis.com/css2?family=Recursive&display=swap');

.main {
  width: 700px;
  border-radius: 15px;
  background-color: #01579b;
}

.header {
  background-color: #424242;
  color: whitesmoke;
  padding: 10px;
  font-size: 28px;
  border-radius: 15px;
  font-family: 'Recursive', sans-serif;
}

.day {
  padding: 15px;
  color: whitesmoke;
  font-family: 'Recursive', sans-serif;
  font-size: 24px;
  font-weight: 600;
}

.temp {
  padding: 15px;
  color: whitesmoke;
  font-family: 'Recursive', sans-serif;
  font-size: 18px;
}

تحسين التصميم البصري لتطبيق الطقس باستخدام CSS

ترتيب البيانات باستخدام Flexbox

لتوزيع البيانات أفقياً بشكل مرتب، يمكن استخدام flexbox كما يلي:

<div className="flex">
  <p className="day">Day: {moment().format('dddd')}</p>
</div>

<div className="flex">
  <p className="temp">Temprature: {weatherData.main.temp} &deg; C</p>
</div>

ثم أضف النمط التالي:

.flex {
  display: flex;
  justify-content: space-between;
}

نسخة أكثر اكتمالاً من مكوّن الطقس

import React from 'react';
import './styles.css';
import moment from 'moment';

const WeatherCard = ({ weatherData }) => (
  <div className="main">
    <p className="header">{weatherData.name}</p>
    <div className="flex">
      <p className="day">{moment().format('dddd')}, <span>{moment().format('LL')}</span></p>
      <p className="description">{weatherData.weather[0].main}</p>
    </div>
    <div className="flex">
      <p className="temp">Temprature: {weatherData.main.temp} &deg; C</p>
      <p className="temp">Humidity: {weatherData.main.humidity} %</p>
    </div>
    <div className="flex">
      <p className="sunrise-sunset">Sunrise: {new Date(weatherData.sys.sunrise * 1000).toLocaleTimeString('en-IN')}</p>
      <p className="sunrise-sunset">Sunset: {new Date(weatherData.sys.sunset * 1000).toLocaleTimeString('en-IN')}</p>
    </div>
  </div>
);

export default WeatherCard;
@import url('https://fonts.googleapis.com/css2?family=Recursive&display=swap');

.main {
  width: 700px;
  border-radius: 20px;
  background-color: #01579b;
}

.top {
  height: 60px;
  background-color: #424242;
  color: whitesmoke;
  padding: 10px;
  border-radius: 20px 20px 0 0;
  font-family: 'Recursive', sans-serif;
  display: flex;
  justify-content: space-between;
}

.header {
  background-color: #424242;
  color: whitesmoke;
  margin: 10px 0 0 10px;
  font-size: 25px;
  border-radius: 20px 20px 0 0;
  font-family: 'Recursive', sans-serif;
}

.day {
  padding: 15px;
  color: whitesmoke;
  font-family: 'Recursive', sans-serif;
  font-size: 24px;
  font-weight: 600;
}

.temp {
  padding: 15px;
  color: whitesmoke;
  font-family: 'Recursive', sans-serif;
  font-size: 18px;
}

.flex {
  display: flex;
  justify-content: space-between;
}

.sunrise-sunset {
  padding: 15px;
  color: whitesmoke;
  font-family: 'Recursive', sans-serif;
  font-size: 16px;
}

.description {
  padding: 15px;
  color: whitesmoke;
  font-family: 'Recursive', sans-serif;
  font-size: 24px;
  font-weight: 600;
}

التصميم النهائي شبه المكتمل لواجهة تطبيق الطقس في React

إضافة زر تحديث لإعادة تحميل البيانات

وجود زر تحديث مفيد حين يرغب المستخدم في إعادة جلب البيانات فوراً، خصوصاً إذا تغيّر الموقع أو أراد تحديث حالة الطقس الحالية.

import React from 'react';
import './styles.css';
import moment from 'moment';
import { Button } from 'semantic-ui-react';

const refresh = () => {
  window.location.reload();
};

const WeatherCard = ({ weatherData }) => (
  <div className="main">
    <div className="top">
      <p className="header">{weatherData.name}</p>
      <Button
        className="button"
        inverted
        color='blue'
        circular
        icon='refresh'
        onClick={refresh}
      />
    </div>

    <div className="flex">
      <p className="day">{moment().format('dddd')}, <span>{moment().format('LL')}</span></p>
      <p className="description">{weatherData.weather[0].main}</p>
    </div>

    <div className="flex">
      <p className="temp">Temprature: {weatherData.main.temp} &deg; C</p>
      <p className="temp">Humidity: {weatherData.main.humidity} %</p>
    </div>

    <div className="flex">
      <p className="sunrise-sunset">Sunrise: {new Date(weatherData.sys.sunrise * 1000).toLocaleTimeString('en-IN')}</p>
      <p className="sunrise-sunset">Sunset: {new Date(weatherData.sys.sunset * 1000).toLocaleTimeString('en-IN')}</p>
    </div>
  </div>
);

export default WeatherCard;
.button {
  width: 35px;
  height: 35px;
}

زر تحديث لإعادة تحميل بيانات الطقس في التطبيق

إضافة شاشة تحميل Loader أثناء جلب البيانات

من أفضل ممارسات تجربة المستخدم أن يرى الزائر مؤشراً بصرياً أثناء انتظار تحميل البيانات، بدلاً من شاشة فارغة.

import { Dimmer, Loader } from 'semantic-ui-react';

<div className="App">
  {(typeof data.main !== 'undefined') ? (
    <Weather weatherData={data} />
  ) : (
    <div>
      <Dimmer active>
        <Loader>Loading..</Loader>
      </Dimmer>
    </div>
  )}
</div>

هذه الإضافة البسيطة تمنح التطبيق مظهراً أكثر احترافية وتقلل من ارتباك المستخدم أثناء انتظار البيانات.

ملخص المفاهيم التي يطبقها هذا المشروع

إدارة الحالة باستخدام State

تم استخدام الحالة لتخزين معلومات متغيرة مثل الإحداثيات وبيانات الطقس. هذه القيم تختلف من مستخدم لآخر حسب موقعه الحالي، لذلك تُعد State جزءاً أساسياً من التطبيق.

نقل البيانات عبر Props

تم جلب البيانات في الملف الرئيسي App.js ثم تمريرها إلى المكوّن الفرعي weather.js باستخدام Props. وهذا يوضح كيف يحافظ React على تدفق بيانات منظم من الأعلى إلى الأسفل.

استخدام React Hooks بدل المكونات الصنفية

بدلاً من الاعتماد على أساليب دورة الحياة التقليدية في Class Components، تم استخدام useState وuseEffect لبناء التطبيق بشكل أبسط وأكثر حداثة.

الاعتماد على مكتبات واجهة جاهزة

ساعدت مكتبة Semantic UI في تسريع بناء عناصر الواجهة، بينما وفرت مكتبة moment طريقة عملية لتنسيق اليوم والتاريخ.

أفكار لتطوير التطبيق مستقبلاً

بعد الانتهاء من النسخة الأساسية، يمكنك توسيع التطبيق وإضافة مزايا أكثر تقدماً، مثل:

  • عرض توقعات الطقس لخمسة أيام.
  • إضافة أيقونات الطقس الديناميكية.
  • إتاحة البحث عن مدينة بدلاً من الاعتماد على الموقع فقط.
  • إضافة دعم الوضع الليلي Dark Mode.
  • تحسين الاستجابة على الهواتف المحمولة.
  • إضافة معالجة أفضل للأخطاء عند رفض إذن الموقع أو تعطل API.

الخلاصة التقنية

بناء تطبيق طقس باستخدام React وReact Hooks يُعد تدريباً عملياً ممتازاً على تطوير واجهات حديثة تتفاعل مع بيانات خارجية في الزمن الحقيقي. هذا المشروع لا يشرح فقط كيفية جلب البيانات وعرضها، بل يرسخ أيضاً مفاهيم مهمة مثل فصل المكونات، إدارة الحالة، التعامل مع العمليات غير المتزامنة، وتحسين تجربة المستخدم بصرياً ووظيفياً. وإذا تم تنفيذ الخطوات بعناية مع تحسينات إضافية في الأداء ومعالجة الأخطاء، فيمكن تحويل هذا المشروع البسيط إلى تطبيق فعلي متكامل قابل للنشر والاستخدام.

اترك تعليقاً

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *