Hello World!
01 about me
I am a final year student at the University of Leeds completing a Bachelor's of Science in Computer Science. I am passionate about designing and developing websites and software applications which led to my focus in this area for my final year project.
I am currently deciding on my next steps after graduation whether to pursue a master's degree or look for a graduate role. Whichever path I choose, I am excited to continue learning and broaden my knowledge in the field.
Some technologies I have worked with are: Python, Java, JavaScript, Flask, C. Feel free to visit my GitHub profile to see some of the projects I have worked on.
Outside of my studies, I enjoy watching a lot football, playing video games and travelling.
02 my projects
Router - GPX
A web application to save and view you and your friend's routes all over the world (offline).
Budget Tracker
An app to track your income and expenses with goal setting and real-time budget calculations.
Budget Tracker
A Flask-based web application for tracking personal finances, featuring income and expense management, goal setting, and real-time budget calculations. Built with Python, Flask, SQLAlchemy, and SQLite, this application demonstrates practical implementation of CRUD operations and database management.
Key Features
- Income and expense tracking
- Financial goal setting and progress monitoring
- Real-time budget calculations and balance tracking
- Duplicate entry prevention
- User feedback system with Flash messages
Code Implementation
SQLAlchemy Models:
from app import db
class Income(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(30), nullable=False)
amount = db.Column(db.Float, nullable=False)
class Expense(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(30), nullable=False)
amount = db.Column(db.Float, nullable=False)
class Goal(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(30))
value = db.Column(db.Float)
def init_db():
db.create_all()
if __name__ == '__main__':
init_db()
Form Classes with Validation:
from flask_wtf import FlaskForm
from wtforms import StringField, FloatField, DecimalField
from wtforms.validators import DataRequired, InputRequired, Length, NumberRange
class IncomeForm(FlaskForm):
name = StringField('Income Name', validators=[
DataRequired(),
Length(max=30)
])
amount = FloatField('Amount', validators=[
DataRequired(),
NumberRange(min=0, max=9999999999999.99)
])
class ExpenseForm(FlaskForm):
name = StringField('Expense Name', validators=[
DataRequired(),
Length(max=30)
])
amount = FloatField('Amount', validators=[
DataRequired(),
NumberRange(min=0, max=9999999999999.99)
])
class GoalForm(FlaskForm):
name = StringField('Name', validators=[
DataRequired(),
Length(max=30)
])
value = DecimalField('Value', validators=[
InputRequired(),
NumberRange(min=0, max=9999999999999.99)
])
Main Dashboard Route Handler:
@app.route('/')
def index():
# Calculate total income and expenses
total_income = db.session.query(
db.func.sum(Income.amount)
).scalar() or 0
total_expense = db.session.query(
db.func.sum(Expense.amount)
).scalar() or 0
# Fetch current goal
temp_goal = Goal.query.first()
goal_name = ""
goal_value = ""
progress = ""
if temp_goal:
goal_name = temp_goal.name
goal_value = temp_goal.value
progress = total_income - total_expense
return render_template('index.html',
total_income=total_income,
total_expense=total_expense,
goal_name=goal_name,
goal_value=goal_value,
progress=progress
)
Income Management System:
@app.route('/income', methods=['GET', 'POST'])
def income():
form = IncomeForm()
if form.validate_on_submit():
name = form.name.data
amount = form.amount.data
# Check for duplicates
dupe_income = Income.query.filter(
func.lower(Income.name) == func.lower(name)
).first()
if dupe_income:
flash('Invalid name (duplicate)', 'danger')
return redirect(url_for('income'))
# Add new income
new_income = Income(name=name, amount=amount)
db.session.add(new_income)
db.session.commit()
flash('Income added successfully', 'success')
return redirect(url_for('income'))
incomes = Income.query.all()
return render_template('income.html',
form=form,
incomes=incomes
)
Goal Management System:
@app.route('/goal', methods=['GET', 'POST'])
def goal():
form = GoalForm()
if form.validate_on_submit():
name = form.name.data
value = form.value.data
# Ensure single goal
dupe_goal = Goal.query.first()
if dupe_goal:
flash('A goal has already been created', 'warning')
return redirect(url_for('goal'))
# Create new goal
temp_goal = Goal(name=name, value=value)
db.session.add(temp_goal)
db.session.commit()
flash('Goal created successfully', 'success')
return redirect(url_for('goal'))
current_goal = Goal.query.first()
return render_template('goal.html',
form=form,
current_goal=current_goal
)
Technology Stack
Backend Framework
ORM
Database
Frontend
Form Handling
Technical Highlights
- Well-organized code structure using Flask framework
- Efficient database management for storing and retrieving data
- Clear separation between different parts of the application for better maintenance
- Smart database queries for quick calculation of totals and summaries
Project Links
View the complete source code on GitHub
Get Typing
A MonkeyType-inspired typing test application built with vanilla JavaScript, HTML, and Tailwind CSS. This project showcases advanced DOM manipulation and real-time calculations while providing an intuitive interface for users to test and improve their typing speed.
Key Features
- Customizable test duration (15, 30, 60, or 120 seconds)
- Multiple difficulty levels with varied word sets
- Real-time WPM calculation and accuracy tracking
- Character-by-character error highlighting
- Dynamic cursor movement and text scrolling
Code Implementation
Real-time WPM Calculation:
calculateWPM() {
const timeElapsed = Date.now() - this.testStart;
const words = [...document.querySelectorAll(".word")];
const typedWords = words.slice(0, words.indexOf(
document.querySelector(".word.current")
) + 1);
const correctWords = typedWords.filter(word => {
const letters = [...word.children];
return letters.every(letter =>
letter.className.includes("correct")
);
});
return Math.round((correctWords.length / timeElapsed) * 60000);
}
Input Processing System:
handleLetterInput(key, currentWord, currentLetter) {
if (currentLetter) {
const isCorrect = key === currentLetter.innerHTML;
currentLetter.classList.add(isCorrect ? "correct" : "incorrect");
currentLetter.classList.remove("current");
if (currentLetter.nextElementSibling) {
currentLetter.nextElementSibling.classList.add("current");
}
} else {
const extraLetter = document.createElement("span");
extraLetter.innerHTML = key;
extraLetter.className = "letter incorrect extra";
currentWord.appendChild(extraLetter);
}
}
Dynamic UI Updates:
updateCursorPosition() {
const nextLetter = document.querySelector(".letter.current");
const nextWord = document.querySelector(".word.current");
if (nextLetter) {
const rect = nextLetter.getBoundingClientRect();
this.cursor.style.top = `${rect.top}px`;
this.cursor.style.left = `${rect.left}px`;
} else if (nextWord) {
const rect = nextWord.getBoundingClientRect();
this.cursor.style.top = `${rect.top}px`;
this.cursor.style.left = `${rect.right}px`;
}
}
Technology Stack
Core Logic
Structure
Styling
Technical Highlights
- Implemented efficient DOM manipulation for real-time text processing and validation
- Built a robust event handling system for keyboard input management
- Developed dynamic UI updates using getBoundingClientRect() for precise cursor positioning
- Created modular class architecture for maintainable and scalable code structure
- Designed flexible difficulty system using separate word arrays for easy customization
Future Development
- Leaderboard and user accounts
- Performance statistics and progress tracking
- Custom word lists and programming snippets
- Additional practice modes and challenges
Project Links
View the source code on GitHub or try the live application .
Router - GPX
This project was developed as a collaborative effort by myself and 5 other students for a university module. A Flask-based web application that allows users to share and track their routes with friends using GPX files. Features subscription-based access and interactive map visualization.
Key Features
- Route Management (GPX file upload and storage)
- User Authentication & Authorization
- Subscription System
Code Implementation
Interactive Map Integration:
calculateWPM() {
let map = L.map('map', {
minZoom: 3,
maxBounds: [[-90,-180], [90,180]]
}).setView([25, 0], 1);
let customLayer = L.geoJson(null, {
onEachFeature: function (feature, layer) {
if (feature.geometry.type === 'Point') {
let coords = feature.geometry.coordinates;
pointMarker = L.marker(L.latLng(coords[1], coords[0])).addTo(map);
pointMarker.bindPopup("Type: Location Marker" +
"
Uploaded by: " + gpxFiles[i][2] +
"
Description: " + gpxFiles[i][3] +
"
Date Uploaded: " + gpxFiles[i][1], customOptions)
}
}
});
Secure File Handling:
handleLetterInput(key, currentWord, currentLetter) {
@app.route('/upload', methods=["GET", "POST"])
@subscription_required
@admin_not_allowed
def upload():
unique_filename = f"{datetime.utcnow().strftime('%Y%m%d%H%M%S')}"
original_filename = secure_filename(route.filename)
if allowed_file(original_filename):
filename = unique_filename + "-" + str(current_user.id) + ".gpx"
file_path = os.path.join(
os.path.abspath(os.path.dirname(__file__)),
app.config['UPLOAD_FOLDER'], filename
)
route.save(file_path)
Technology Stack
Backend Framework
Frontend
Interactive Features
Main Database
Technical Highlights
- Implemented secure user authentication with role-based access control
- Built interactive map visualization using Leaflet.js and custom GeoJSON layers
- Developed encrypted payment processing system with subscription management
- Created social networking features with friend relationships and route sharing
- Built comprehensive admin panel for user and subscription management
Project Links
View the source code on GitHub.
Designed and built by Fathan Raedaya © 2024