Skip to content
This repository was archived by the owner on May 2, 2022. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 3 additions & 2 deletions src/common/Card.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import React from "react";
import { NavLink } from "react-router-dom";
import { arrayOfIds } from "../features/subscriptions/types";
import UserImage from "./UserImage";

interface CardProps {
id?: string;
image?: string;
username?: string;
followings?: string;
followers?: string;
followings?: arrayOfIds | null;
followers?: arrayOfIds | null;
children: React.ReactNode;
}

Expand Down
4 changes: 2 additions & 2 deletions src/common/services/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ export function setTokenHeader(token: string | boolean): void {
* @param {string} path - the route path/endpoint
* @param {object} data - (optional) data in JSON form for POST requests
*/
export const apiCall = (
export const apiCall = <T>(
method: Method,
url: string,
data?: any
): AxiosPromise<unknown> => {
): AxiosPromise<T> => {
return new Promise((resolve, reject) => {
return axios
.request({ method, url, data })
Expand Down
11 changes: 4 additions & 7 deletions src/features/actions.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
import { User, UserFollowers } from "./user/types";
import { RECEIVE_ENTITIES } from "./actionTypes";
import { Tags } from "./tags/types";

export interface Users {
id: number;
username: string;
image: string;
}

export interface Readings {
id: number;
title: string;
Expand All @@ -22,7 +17,7 @@ export interface Readings {
}

export interface Entities {
user?: Users;
users?: User[];
readings?: Readings;
tags?: Tags;
}
Expand All @@ -35,6 +30,8 @@ export interface ReceiveEntitiesAction {
list: any;
id?: any;
user_id?: number | null;
users?: User[];
userFollowers?: UserFollowers;
}

export const receiveEntities = (
Expand Down
7 changes: 1 addition & 6 deletions src/features/auth/types.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
import { SET_CURRENT_USER } from "../actionTypes";
import { AlertActionTypes } from "../alerts/types";

export interface User {
id: number | null;
username: string | null;
image: string | null;
}
import { User } from "../user/types";

export interface AuthState {
isAuthenticated: boolean;
Expand Down
8 changes: 4 additions & 4 deletions src/features/globalReadings/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ const getTagReadings = (readings: any[], tag_id: number): any[] => {
export const getReadings = (
state: any,
list: string,
fav: any,
outdated: any,
tag_id: number
fav?: any,
outdated?: any,
tag_id?: number
): any[] | void => {
// give time for readingsByList items to load
if (
Expand Down Expand Up @@ -56,7 +56,7 @@ export const getReadingById = (state: any, list: string, id: number): any => {
export const getWebsites = (
state: any,
list: string,
tag_id: number
tag_id?: number
): { [k: string]: any } => {
let websiteCount: { [k: string]: any } = {};

Expand Down
17 changes: 11 additions & 6 deletions src/features/subscriptions/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,17 @@ import {
postingNewSubscription,
fetchingSubscriptionsIfNeeded,
} from "./types";
import { UserFollowers } from "../user/types";
import { AxiosResponse } from "axios";

const { addAlert } = alerts.actions;

export const loadSubscriptions = (users: any, id: number) => ({
export const loadSubscriptions = (
userFollowers: AxiosResponse<UserFollowers>,
id: string | number
) => ({
type: LOAD_SUBSCRIPTIONS,
users,
userFollowers,
id,
});

Expand All @@ -33,9 +38,9 @@ export const removeSubscriptions = (id: number, user_id: number | null) => ({
});

export const fetchSubscriptions =
(user_id: number): fetchingSubscriptions =>
(user_id: string | number): fetchingSubscriptions =>
async (dispatch) => {
return apiCall("get", `/users/${user_id}/subscriptions`)
return apiCall<UserFollowers>("get", `/users/${user_id}/subscriptions`)
.then((res) => dispatch(loadSubscriptions(res, user_id)))
.catch((err) =>
dispatch(addAlert({ message: err.message, type: "danger" }))
Expand Down Expand Up @@ -79,7 +84,7 @@ export const postNewSubscription =

const shouldFetchSubscriptions = (
state: any,
id: number
id: string | number
): boolean | undefined => {
const subscriptions = state.subscriptions[id];
const upToDate = state.subscriptions.upToDate;
Expand All @@ -89,7 +94,7 @@ const shouldFetchSubscriptions = (
};

export const fetchSubscriptionsIfNeeded = (
id: number
id: string | number
): fetchingSubscriptionsIfNeeded => {
return (dispatch, getState) => {
if (shouldFetchSubscriptions(getState(), id)) {
Expand Down
4 changes: 2 additions & 2 deletions src/features/subscriptions/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export const getSubscriptions = (

export const getFollowers = (
state: any,
id: number
id: number | string
): arrayOfIds | undefined => {
if (state.subscriptions[id]) {
return state.subscriptions[id].followers;
Expand All @@ -18,7 +18,7 @@ export const getFollowers = (

export const getFollowings = (
state: any,
id: number
id: number | string
): arrayOfIds | undefined => {
if (state.subscriptions[id]) {
return state.subscriptions[id].following;
Expand Down
5 changes: 3 additions & 2 deletions src/features/subscriptions/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@ import {
REMOVE_SUBSCRIPTIONS,
} from "../actionTypes";
import { RootState } from "../rootReducer";
import { UserFollowers } from "../user/types";

export type SubscriptionState = any;

interface LoadSubscriptionAction {
export interface LoadSubscriptionAction {
type: typeof LOAD_SUBSCRIPTIONS;
users: any;
id: number;
user_id: never;
userFollowers: UserFollowers;
}

interface AddSubscriptionAction {
Expand Down
4 changes: 2 additions & 2 deletions src/features/tags/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export const loadTags = (tags: Tags) => ({
tags,
});

export const fetchTags = (list: string, id: number): fetchingTags => {
export const fetchTags = (list: string, id: string): fetchingTags => {
return (dispatch, getState) => {
if (list === "global") {
dispatch(addLoader("tags"));
Expand Down Expand Up @@ -121,7 +121,7 @@ const shouldFetchTags = (state: any, list: string) => {

export const fetchTagsIfNeeded = (
list: string,
id: number
id: string
): fetchingTagsIfNeeded => {
return (dispatch, getState) => {
if (shouldFetchTags(getState(), list)) {
Expand Down
2 changes: 1 addition & 1 deletion src/features/tags/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export type TagsActionTypes =
| AddTagAction
| RemoveTagAction;

interface AddTagAction {
export interface AddTagAction {
type: typeof ADD_TAG;
id: number;
user_id: number | null;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import { ReceiveEntitiesAction } from "./../actions";
import { RECEIVE_ENTITIES, ADD_TAG } from "../actionTypes";
import { Tags, AddTagAction } from "./../tags/types";

const getIds = (tags) => {
const getIds = (tags: Tags): number[] => {
return Object.values(tags).map((tag) => tag.id);
};

const tagsByList = (state = {}, action) => {
export type TagsByListActionTypes = ReceiveEntitiesAction | AddTagAction;

const tagsByList = (state: any = {}, action: TagsByListActionTypes) => {
switch (action.type) {
case RECEIVE_ENTITIES:
const { entities } = action.payload;
Expand Down
37 changes: 28 additions & 9 deletions src/features/user/UserAside.js → src/features/user/UserAside.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { Component } from "react";
import { NavLink } from "react-router-dom";
import { connect } from "react-redux";
import { NavLink, RouteComponentProps } from "react-router-dom";
import { connect, ConnectedProps } from "react-redux";
import subscriptions from "../subscriptions";
import globalReadings from "../globalReadings";
import tags, { TagsAside } from "../tags";
Expand All @@ -9,12 +9,25 @@ import { getUserById } from "./selectors";
import Card from "../../common/Card";
import Subscribe from "../../common/Subscribe";
import ReadingStats from "../../common/ReadingsStats";
import { RootState } from "../rootReducer";

const { getReadings, getWebsites, getUserReadingsInNeedOfUpdate } =
globalReadings.selectors;
const { getFollowers, getFollowings } = subscriptions.selectors;

class UserAside extends Component {
type UserAsideProps = PropsFromRedux & OwnProps;

interface matchProps {
id: string;
}

interface OwnProps extends RouteComponentProps<matchProps> {
key: number;
id: number;
fav: any;
}

class UserAside extends Component<UserAsideProps> {
componentDidMount() {
if (this.props.match) {
this.props.fetchTagsIfNeeded(
Expand All @@ -32,7 +45,7 @@ class UserAside extends Component {
}
}

componentDidUpdate(prevProps) {
componentDidUpdate(prevProps: UserAsideProps) {
if (
this.props.match &&
prevProps.match &&
Expand Down Expand Up @@ -73,7 +86,7 @@ class UserAside extends Component {
totalFavorites = 0,
totalOutdated = 0;

let u = {};
let u: any = {};
if (user) u = user;
else u = currentUser;
// if (!readings) u = currentUser;
Expand All @@ -85,7 +98,9 @@ class UserAside extends Component {

totalReadings = readings.length;
totalWebsites = Object.keys(websites).length;
totalBooks = totalWords.toFixed(2);
// totalWords.toFixed(2); returns string
// Math.round(totalWords * 1e2) / 1e2; returns number
totalBooks = Math.round(totalWords * 1e2) / 1e2;

for (const prop in websites) {
if (websites[prop] > maxReads) {
Expand Down Expand Up @@ -182,7 +197,7 @@ class UserAside extends Component {
}
}

function mapStateToProps(state, ownProps) {
function mapStateToProps(state: RootState, ownProps: OwnProps) {
return {
readings: getReadings(state, ownProps.match.params.id),
websites: getWebsites(state, ownProps.match.params.id),
Expand All @@ -200,9 +215,13 @@ function mapStateToProps(state, ownProps) {
};
}

export default connect(mapStateToProps, {
const connector = connect(mapStateToProps, {
...subscriptions.actions,
...globalReadings.actions,
...tags.actions,
fetchUserIfNeeded,
})(UserAside);
});

type PropsFromRedux = ConnectedProps<typeof connector>;

export default connector(UserAside);
30 changes: 0 additions & 30 deletions src/features/user/actions.js

This file was deleted.

36 changes: 36 additions & 0 deletions src/features/user/actions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { AxiosResponse } from "axios";
import { apiCall } from "../../common/services/api";
import alerts from "../alerts";
import { LOAD_USER } from "../actionTypes";
import { fetchingUser, fetchingUserIfNeeded, User } from "./types";

const { addAlert } = alerts.actions;

export const loadUser = (users: AxiosResponse<User[]>) => ({
type: LOAD_USER,
users,
});

export const fetchUser = (id: string | number): fetchingUser => {
return (dispatch) => {
return apiCall<User[]>("get", `/users/${id}`)
.then((res) => dispatch(loadUser(res)))
.catch((err) =>
dispatch(addAlert({ message: err.message, type: "danger" }))
);
};
};
const shouldFetchUser = (state: any, id: string | number) => {
const user = state.user[id];
if (!user) return true;
};

export const fetchUserIfNeeded = (
id: string | number
): fetchingUserIfNeeded => {
return (dispatch, getState) => {
if (shouldFetchUser(getState(), id)) {
return dispatch(fetchUser(id));
}
};
};
File renamed without changes.
Loading